From patchwork Sun Jun 21 22:54:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ioana Ciornei X-Patchwork-Id: 217433 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D4A01C433E0 for ; Sun, 21 Jun 2020 22:56:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A745E20732 for ; Sun, 21 Jun 2020 22:56:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730790AbgFUW4B (ORCPT ); Sun, 21 Jun 2020 18:56:01 -0400 Received: from inva021.nxp.com ([92.121.34.21]:54266 "EHLO inva021.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726414AbgFUW4A (ORCPT ); Sun, 21 Jun 2020 18:56:00 -0400 Received: from inva021.nxp.com (localhost [127.0.0.1]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id D19B02007B8; Mon, 22 Jun 2020 00:55:58 +0200 (CEST) Received: from inva024.eu-rdc02.nxp.com (inva024.eu-rdc02.nxp.com [134.27.226.22]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id C4D1A20059D; Mon, 22 Jun 2020 00:55:58 +0200 (CEST) Received: from fsr-ub1864-126.ea.freescale.net (fsr-ub1864-126.ea.freescale.net [10.171.82.212]) by inva024.eu-rdc02.nxp.com (Postfix) with ESMTP id 4D59920414; Mon, 22 Jun 2020 00:55:58 +0200 (CEST) From: Ioana Ciornei To: netdev@vger.kernel.org, davem@davemloft.net Cc: vladimir.oltean@nxp.com, claudiu.manoil@nxp.com, alexandru.marginean@nxp.com, michael@walle.cc, andrew@lunn.ch, linux@armlinux.org.uk, f.fainelli@gmail.com, olteanv@gmail.com, Russell King , Ioana Ciornei Subject: [PATCH net-next v3 1/9] net: phylink: add interface to configure clause 22 PCS PHY Date: Mon, 22 Jun 2020 01:54:43 +0300 Message-Id: <20200621225451.12435-2-ioana.ciornei@nxp.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200621225451.12435-1-ioana.ciornei@nxp.com> References: <20200621225451.12435-1-ioana.ciornei@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Russell King Add helper for clause 22 PCS configuration via the MII bus. Apart from applying the advertisements, the pcs_config helper also sets up the BMCR_ANENABLE depending on the in-band AN state. Signed-off-by: Russell King Signed-off-by: Ioana Ciornei --- Changes in v2: - none Changes in v3: - none drivers/net/phy/phylink.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/phylink.h | 3 +++ 2 files changed, 40 insertions(+) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 7ce787c227b3..f04ccdedda40 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -2267,6 +2267,43 @@ int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, } EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement); +/** + * phylink_mii_c22_pcs_config() - configure clause 22 PCS + * @pcs: a pointer to a &struct mdio_device. + * @mode: link autonegotiation mode + * @interface: the PHY interface mode being configured + * @advertising: the ethtool advertisement mask + * + * Configure a Clause 22 PCS PHY with the appropriate negotiation + * parameters for the @mode, @interface and @advertising parameters. + * Returns negative error number on failure, zero if the advertisement + * has not changed, or positive if there is a change. + */ +int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising) +{ + bool changed; + u16 bmcr; + int ret; + + ret = phylink_mii_c22_pcs_set_advertisement(pcs, interface, + advertising); + if (ret < 0) + return ret; + + changed = ret > 0; + + bmcr = mode == MLO_AN_INBAND ? BMCR_ANENABLE : 0; + ret = mdiobus_modify(pcs->bus, pcs->addr, MII_BMCR, + BMCR_ANENABLE, bmcr); + if (ret < 0) + return ret; + + return changed ? 1 : 0; +} +EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_config); + /** * phylink_mii_c22_pcs_an_restart() - restart 802.3z autonegotiation * @pcs: a pointer to a &struct mdio_device. diff --git a/include/linux/phylink.h b/include/linux/phylink.h index cc5b452a184e..d979832d0c71 100644 --- a/include/linux/phylink.h +++ b/include/linux/phylink.h @@ -410,6 +410,9 @@ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, phy_interface_t interface, const unsigned long *advertising); +int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising); void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs); void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs, From patchwork Sun Jun 21 22:54:45 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ioana Ciornei X-Patchwork-Id: 217432 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E7832C433E1 for ; Sun, 21 Jun 2020 22:56:04 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BEFD820732 for ; Sun, 21 Jun 2020 22:56:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730831AbgFUW4E (ORCPT ); Sun, 21 Jun 2020 18:56:04 -0400 Received: from inva020.nxp.com ([92.121.34.13]:36530 "EHLO inva020.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726450AbgFUW4B (ORCPT ); Sun, 21 Jun 2020 18:56:01 -0400 Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id EE5651A08BE; Mon, 22 Jun 2020 00:55:59 +0200 (CEST) Received: from inva024.eu-rdc02.nxp.com (inva024.eu-rdc02.nxp.com [134.27.226.22]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id E23DB1A08BB; Mon, 22 Jun 2020 00:55:59 +0200 (CEST) Received: from fsr-ub1864-126.ea.freescale.net (fsr-ub1864-126.ea.freescale.net [10.171.82.212]) by inva024.eu-rdc02.nxp.com (Postfix) with ESMTP id 69BDC20414; Mon, 22 Jun 2020 00:55:59 +0200 (CEST) From: Ioana Ciornei To: netdev@vger.kernel.org, davem@davemloft.net Cc: vladimir.oltean@nxp.com, claudiu.manoil@nxp.com, alexandru.marginean@nxp.com, michael@walle.cc, andrew@lunn.ch, linux@armlinux.org.uk, f.fainelli@gmail.com, olteanv@gmail.com, Ioana Ciornei Subject: [PATCH net-next v3 3/9] net: mdiobus: add clause 45 mdiobus write accessor Date: Mon, 22 Jun 2020 01:54:45 +0300 Message-Id: <20200621225451.12435-4-ioana.ciornei@nxp.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200621225451.12435-1-ioana.ciornei@nxp.com> References: <20200621225451.12435-1-ioana.ciornei@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add the locked variant of the clause 45 mdiobus write accessor - mdiobus_c45_write(). Signed-off-by: Ioana Ciornei --- Changes in v2: - none Changes in v3: - none include/linux/mdio.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/linux/mdio.h b/include/linux/mdio.h index 36d2e0673d03..323f1d1fa271 100644 --- a/include/linux/mdio.h +++ b/include/linux/mdio.h @@ -357,6 +357,12 @@ static inline int mdiobus_c45_read(struct mii_bus *bus, int prtad, int devad, return mdiobus_read(bus, prtad, mdiobus_c45_addr(devad, regnum)); } +static inline int mdiobus_c45_write(struct mii_bus *bus, int prtad, int devad, + u16 regnum, u16 val) +{ + return mdiobus_write(bus, prtad, mdiobus_c45_addr(devad, regnum), val); +} + int mdiobus_register_device(struct mdio_device *mdiodev); int mdiobus_unregister_device(struct mdio_device *mdiodev); bool mdiobus_is_registered_device(struct mii_bus *bus, int addr); From patchwork Sun Jun 21 22:54:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ioana Ciornei X-Patchwork-Id: 217430 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-15.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8CB0CC433DF for ; Sun, 21 Jun 2020 22:56:12 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 519C723339 for ; Sun, 21 Jun 2020 22:56:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730879AbgFUW4L (ORCPT ); Sun, 21 Jun 2020 18:56:11 -0400 Received: from inva020.nxp.com ([92.121.34.13]:36546 "EHLO inva020.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726464AbgFUW4E (ORCPT ); Sun, 21 Jun 2020 18:56:04 -0400 Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 7039C1A08BF; Mon, 22 Jun 2020 00:56:00 +0200 (CEST) Received: from inva024.eu-rdc02.nxp.com (inva024.eu-rdc02.nxp.com [134.27.226.22]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 6BCCD1A08BB; Mon, 22 Jun 2020 00:56:00 +0200 (CEST) Received: from fsr-ub1864-126.ea.freescale.net (fsr-ub1864-126.ea.freescale.net [10.171.82.212]) by inva024.eu-rdc02.nxp.com (Postfix) with ESMTP id F121220414; Mon, 22 Jun 2020 00:55:59 +0200 (CEST) From: Ioana Ciornei To: netdev@vger.kernel.org, davem@davemloft.net Cc: vladimir.oltean@nxp.com, claudiu.manoil@nxp.com, alexandru.marginean@nxp.com, michael@walle.cc, andrew@lunn.ch, linux@armlinux.org.uk, f.fainelli@gmail.com, olteanv@gmail.com, Ioana Ciornei Subject: [PATCH net-next v3 4/9] net: phy: add Lynx PCS module Date: Mon, 22 Jun 2020 01:54:46 +0300 Message-Id: <20200621225451.12435-5-ioana.ciornei@nxp.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200621225451.12435-1-ioana.ciornei@nxp.com> References: <20200621225451.12435-1-ioana.ciornei@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add a Lynx PCS module which exposes the necessary operations to drive the PCS using PHYLINK. The majority of the code is extracted from the Felix DSA driver, which will be also modified in a later patch, and exposed as a separate module for code reusability purposes. At the moment, USXGMII (only with in-band AN and speeds up to 2500), SGMII, QSGMII and 2500Base-X (only w/o in-band AN) are supported by the Lynx PCS module since these were also supported by Felix. The module can only be enabled by the drivers in need and not user selectable. Signed-off-by: Ioana Ciornei --- Changes in v2: * got rid of the mdio_lynx_pcs structure and directly exported the functions without the need of an indirection * solved the broken allmodconfig build test by making the module tristate instead of bool Changes in v3: * renamed the file to pcs-lynx.c MAINTAINERS | 7 + drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/pcs-lynx.c | 337 +++++++++++++++++++++++++++++++++++++ include/linux/pcs-lynx.h | 25 +++ 5 files changed, 376 insertions(+) create mode 100644 drivers/net/phy/pcs-lynx.c create mode 100644 include/linux/pcs-lynx.h diff --git a/MAINTAINERS b/MAINTAINERS index 301330e02bca..850d8b4f2d29 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10168,6 +10168,13 @@ S: Maintained W: http://linux-test-project.github.io/ T: git git://github.com/linux-test-project/ltp.git +LYNX PCS MODULE +M: Ioana Ciornei +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/phy/pcs-lynx.c +F: include/linux/pcs-lynx.h + M68K ARCHITECTURE M: Geert Uytterhoeven L: linux-m68k@lists.linux-m68k.org diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index f25702386d83..3a573afb21a3 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -235,6 +235,12 @@ config MDIO_XPCS This module provides helper functions for Synopsys DesignWare XPCS controllers. +config PCS_LYNX + tristate + help + This module provides helper functions for Lynx PCS enablement + representing the PCS as an MDIO device. + endif endif diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index dc9e53b511d6..15ea3345fe3c 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o obj-$(CONFIG_MDIO_XGENE) += mdio-xgene.o obj-$(CONFIG_MDIO_XPCS) += mdio-xpcs.o +obj-$(CONFIG_PCS_LYNX) += pcs-lynx.o obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o diff --git a/drivers/net/phy/pcs-lynx.c b/drivers/net/phy/pcs-lynx.c new file mode 100644 index 000000000000..23bdd9db4340 --- /dev/null +++ b/drivers/net/phy/pcs-lynx.c @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* Copyright 2020 NXP + * Lynx PCS MDIO helpers + */ + +#include +#include +#include + +#define SGMII_CLOCK_PERIOD_NS 8 /* PCS is clocked at 125 MHz */ +#define SGMII_LINK_TIMER_VAL(ns) ((u32)((ns) / SGMII_CLOCK_PERIOD_NS)) + +#define SGMII_AN_LINK_TIMER_NS 1600000 /* defined by SGMII spec */ + +#define SGMII_LINK_TIMER_LO 0x12 +#define SGMII_LINK_TIMER_HI 0x13 +#define SGMII_IF_MODE 0x14 +#define SGMII_IF_MODE_SGMII_EN BIT(0) +#define SGMII_IF_MODE_USE_SGMII_AN BIT(1) +#define SGMII_IF_MODE_SPEED(x) (((x) << 2) & GENMASK(3, 2)) +#define SGMII_IF_MODE_SPEED_MSK GENMASK(3, 2) +#define SGMII_IF_MODE_DUPLEX BIT(4) + +#define USXGMII_ADVERTISE_LSTATUS(x) (((x) << 15) & BIT(15)) +#define USXGMII_ADVERTISE_FDX BIT(12) +#define USXGMII_ADVERTISE_SPEED(x) (((x) << 9) & GENMASK(11, 9)) + +#define USXGMII_LPA_LSTATUS(lpa) ((lpa) >> 15) +#define USXGMII_LPA_DUPLEX(lpa) (((lpa) & GENMASK(12, 12)) >> 12) +#define USXGMII_LPA_SPEED(lpa) (((lpa) & GENMASK(11, 9)) >> 9) + +enum usxgmii_speed { + USXGMII_SPEED_10 = 0, + USXGMII_SPEED_100 = 1, + USXGMII_SPEED_1000 = 2, + USXGMII_SPEED_2500 = 4, +}; + +enum sgmii_speed { + SGMII_SPEED_10 = 0, + SGMII_SPEED_100 = 1, + SGMII_SPEED_1000 = 2, + SGMII_SPEED_2500 = 2, +}; + +static void lynx_pcs_an_restart_usxgmii(struct mdio_device *pcs) +{ + mdiobus_c45_write(pcs->bus, pcs->addr, + MDIO_MMD_VEND2, MII_BMCR, + BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART); +} + +void lynx_pcs_an_restart(struct mdio_device *pcs, phy_interface_t ifmode) +{ + switch (ifmode) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + phylink_mii_c22_pcs_an_restart(pcs); + break; + case PHY_INTERFACE_MODE_USXGMII: + lynx_pcs_an_restart_usxgmii(pcs); + break; + case PHY_INTERFACE_MODE_2500BASEX: + break; + default: + dev_err(&pcs->dev, "Invalid PCS interface type %s\n", + phy_modes(ifmode)); + break; + } +} +EXPORT_SYMBOL(lynx_pcs_an_restart); + +static void lynx_pcs_get_state_usxgmii(struct mdio_device *pcs, + struct phylink_link_state *state) +{ + struct mii_bus *bus = pcs->bus; + int addr = pcs->addr; + int status, lpa; + + status = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_BMSR); + if (status < 0) + return; + + state->link = !!(status & MDIO_STAT1_LSTATUS); + state->an_complete = !!(status & MDIO_AN_STAT1_COMPLETE); + if (!state->link || !state->an_complete) + return; + + lpa = mdiobus_c45_read(bus, addr, MDIO_MMD_VEND2, MII_LPA); + if (lpa < 0) + return; + + switch (USXGMII_LPA_SPEED(lpa)) { + case USXGMII_SPEED_10: + state->speed = SPEED_10; + break; + case USXGMII_SPEED_100: + state->speed = SPEED_100; + break; + case USXGMII_SPEED_1000: + state->speed = SPEED_1000; + break; + case USXGMII_SPEED_2500: + state->speed = SPEED_2500; + break; + default: + break; + } + + if (USXGMII_LPA_DUPLEX(lpa)) + state->duplex = DUPLEX_FULL; + else + state->duplex = DUPLEX_HALF; +} + +static void lynx_pcs_get_state_2500basex(struct mdio_device *pcs, + struct phylink_link_state *state) +{ + struct mii_bus *bus = pcs->bus; + int addr = pcs->addr; + int bmsr, lpa; + + bmsr = mdiobus_read(bus, addr, MII_BMSR); + lpa = mdiobus_read(bus, addr, MII_LPA); + if (bmsr < 0 || lpa < 0) { + state->link = false; + return; + } + + state->link = !!(bmsr & BMSR_LSTATUS); + state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); + if (!state->link) + return; + + state->speed = SPEED_2500; + state->pause |= MLO_PAUSE_TX | MLO_PAUSE_RX; +} + +void lynx_pcs_get_state(struct mdio_device *pcs, phy_interface_t ifmode, + struct phylink_link_state *state) +{ + switch (ifmode) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + phylink_mii_c22_pcs_get_state(pcs, state); + break; + case PHY_INTERFACE_MODE_2500BASEX: + lynx_pcs_get_state_2500basex(pcs, state); + break; + case PHY_INTERFACE_MODE_USXGMII: + lynx_pcs_get_state_usxgmii(pcs, state); + break; + default: + break; + } + + dev_dbg(&pcs->dev, + "mode=%s/%s/%s link=%u an_enabled=%u an_complete=%u\n", + phy_modes(ifmode), + phy_speed_to_str(state->speed), + phy_duplex_to_str(state->duplex), + state->link, state->an_enabled, state->an_complete); +} +EXPORT_SYMBOL(lynx_pcs_get_state); + +static int lynx_pcs_config_sgmii(struct mdio_device *pcs, unsigned int mode, + const unsigned long *advertising) +{ + struct mii_bus *bus = pcs->bus; + int addr = pcs->addr; + u16 if_mode; + int err; + + /* SGMII spec requires tx_config_Reg[15:0] to be exactly 0x4001 + * for the MAC PCS in order to acknowledge the AN. + */ + mdiobus_write(bus, addr, MII_ADVERTISE, + ADVERTISE_SGMII | ADVERTISE_LPACK); + + if_mode = SGMII_IF_MODE_SGMII_EN; + if (mode == MLO_AN_INBAND) { + u32 link_timer; + + if_mode |= SGMII_IF_MODE_USE_SGMII_AN; + + /* Adjust link timer for SGMII */ + link_timer = SGMII_LINK_TIMER_VAL(SGMII_AN_LINK_TIMER_NS); + mdiobus_write(bus, addr, SGMII_LINK_TIMER_LO, link_timer & 0xffff); + mdiobus_write(bus, addr, SGMII_LINK_TIMER_HI, link_timer >> 16); + } + mdiobus_modify(bus, addr, SGMII_IF_MODE, + SGMII_IF_MODE_SGMII_EN | SGMII_IF_MODE_USE_SGMII_AN, + if_mode); + + err = phylink_mii_c22_pcs_config(pcs, mode, PHY_INTERFACE_MODE_SGMII, + advertising); + return err; +} + +static int lynx_pcs_config_usxgmii(struct mdio_device *pcs, unsigned int mode, + const unsigned long *advertising) +{ + struct mii_bus *bus = pcs->bus; + int addr = pcs->addr; + + /* Configure device ability for the USXGMII Replicator */ + mdiobus_c45_write(bus, addr, MDIO_MMD_VEND2, MII_ADVERTISE, + USXGMII_ADVERTISE_SPEED(USXGMII_SPEED_2500) | + USXGMII_ADVERTISE_LSTATUS(1) | + ADVERTISE_SGMII | + ADVERTISE_LPACK | + USXGMII_ADVERTISE_FDX); + return 0; +} + +int lynx_pcs_config(struct mdio_device *pcs, unsigned int mode, + phy_interface_t ifmode, + const unsigned long *advertising) +{ + switch (ifmode) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + lynx_pcs_config_sgmii(pcs, mode, advertising); + break; + case PHY_INTERFACE_MODE_2500BASEX: + /* 2500Base-X only works without in-band AN, + * thus nothing to do here + */ + break; + case PHY_INTERFACE_MODE_USXGMII: + lynx_pcs_config_usxgmii(pcs, mode, advertising); + break; + default: + return -EOPNOTSUPP; + } + + return 0; +} +EXPORT_SYMBOL(lynx_pcs_config); + +static void lynx_pcs_link_up_sgmii(struct mdio_device *pcs, unsigned int mode, + int speed, int duplex) +{ + struct mii_bus *bus = pcs->bus; + u16 if_mode = 0, sgmii_speed; + int addr = pcs->addr; + + /* The PCS needs to be configured manually only + * when not operating on in-band mode + */ + if (mode == MLO_AN_INBAND) + return; + + if (duplex == DUPLEX_HALF) + if_mode |= SGMII_IF_MODE_DUPLEX; + + switch (speed) { + case SPEED_1000: + sgmii_speed = SGMII_SPEED_1000; + break; + case SPEED_100: + sgmii_speed = SGMII_SPEED_100; + break; + case SPEED_10: + sgmii_speed = SGMII_SPEED_10; + break; + case SPEED_UNKNOWN: + /* Silently don't do anything */ + return; + default: + dev_err(&pcs->dev, "Invalid PCS speed %d\n", speed); + return; + } + if_mode |= SGMII_IF_MODE_SPEED(sgmii_speed); + + mdiobus_modify(bus, addr, SGMII_IF_MODE, + SGMII_IF_MODE_DUPLEX | SGMII_IF_MODE_SPEED_MSK, + if_mode); +} + +/* 2500Base-X is SerDes protocol 7 on Felix and 6 on ENETC. It is a SerDes lane + * clocked at 3.125 GHz which encodes symbols with 8b/10b and does not have + * auto-negotiation of any link parameters. Electrically it is compatible with + * a single lane of XAUI. + * The hardware reference manual wants to call this mode SGMII, but it isn't + * really, since the fundamental features of SGMII: + * - Downgrading the link speed by duplicating symbols + * - Auto-negotiation + * are not there. + * The speed is configured at 1000 in the IF_MODE because the clock frequency + * is actually given by a PLL configured in the Reset Configuration Word (RCW). + * Since there is no difference between fixed speed SGMII w/o AN and 802.3z w/o + * AN, we call this PHY interface type 2500Base-X. In case a PHY negotiates a + * lower link speed on line side, the system-side interface remains fixed at + * 2500 Mbps and we do rate adaptation through pause frames. + */ +static void lynx_pcs_link_up_2500basex(struct mdio_device *pcs, + unsigned int mode, + int speed, int duplex) +{ + struct mii_bus *bus = pcs->bus; + int addr = pcs->addr; + + if (mode == MLO_AN_INBAND) { + dev_err(&pcs->dev, "AN not supported for 2500BaseX\n"); + return; + } + + mdiobus_write(bus, addr, SGMII_IF_MODE, + SGMII_IF_MODE_SGMII_EN | + SGMII_IF_MODE_SPEED(SGMII_SPEED_2500)); +} + +void lynx_pcs_link_up(struct mdio_device *pcs, unsigned int mode, + phy_interface_t interface, + int speed, int duplex) +{ + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + case PHY_INTERFACE_MODE_QSGMII: + lynx_pcs_link_up_sgmii(pcs, mode, speed, duplex); + break; + case PHY_INTERFACE_MODE_2500BASEX: + lynx_pcs_link_up_2500basex(pcs, mode, speed, duplex); + break; + case PHY_INTERFACE_MODE_USXGMII: + /* At the moment, only in-band AN is supported for USXGMII + * so nothing to do in link_up + */ + break; + default: + break; + } +} +EXPORT_SYMBOL(lynx_pcs_link_up); + +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/include/linux/pcs-lynx.h b/include/linux/pcs-lynx.h new file mode 100644 index 000000000000..336fccb8c55f --- /dev/null +++ b/include/linux/pcs-lynx.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* Copyright 2020 NXP + * Lynx PCS helpers + */ + +#ifndef __LINUX_PCS_LYNX_H +#define __LINUX_PCS_LYNX_H + +#include +#include + +void lynx_pcs_an_restart(struct mdio_device *pcs, phy_interface_t ifmode); + +void lynx_pcs_get_state(struct mdio_device *pcs, phy_interface_t ifmode, + struct phylink_link_state *state); + +int lynx_pcs_config(struct mdio_device *pcs, unsigned int mode, + phy_interface_t ifmode, + const unsigned long *advertising); + +void lynx_pcs_link_up(struct mdio_device *pcs, unsigned int mode, + phy_interface_t interface, + int speed, int duplex); + +#endif /* __LINUX_PCS_LYNX_H */ From patchwork Sun Jun 21 22:54:47 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ioana Ciornei X-Patchwork-Id: 217429 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7AFD8C433E0 for ; Sun, 21 Jun 2020 22:56:17 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 5DD5A23339 for ; Sun, 21 Jun 2020 22:56:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730899AbgFUW4Q (ORCPT ); Sun, 21 Jun 2020 18:56:16 -0400 Received: from inva021.nxp.com ([92.121.34.21]:54342 "EHLO inva021.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726432AbgFUW4D (ORCPT ); Sun, 21 Jun 2020 18:56:03 -0400 Received: from inva021.nxp.com (localhost [127.0.0.1]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id 079082007BB; Mon, 22 Jun 2020 00:56:01 +0200 (CEST) Received: from inva024.eu-rdc02.nxp.com (inva024.eu-rdc02.nxp.com [134.27.226.22]) by inva021.eu-rdc02.nxp.com (Postfix) with ESMTP id E96DD20059D; Mon, 22 Jun 2020 00:56:00 +0200 (CEST) Received: from fsr-ub1864-126.ea.freescale.net (fsr-ub1864-126.ea.freescale.net [10.171.82.212]) by inva024.eu-rdc02.nxp.com (Postfix) with ESMTP id 7A93E20414; Mon, 22 Jun 2020 00:56:00 +0200 (CEST) From: Ioana Ciornei To: netdev@vger.kernel.org, davem@davemloft.net Cc: vladimir.oltean@nxp.com, claudiu.manoil@nxp.com, alexandru.marginean@nxp.com, michael@walle.cc, andrew@lunn.ch, linux@armlinux.org.uk, f.fainelli@gmail.com, olteanv@gmail.com, Ioana Ciornei Subject: [PATCH net-next v3 5/9] net: dsa: add support for phylink_pcs_ops Date: Mon, 22 Jun 2020 01:54:47 +0300 Message-Id: <20200621225451.12435-6-ioana.ciornei@nxp.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200621225451.12435-1-ioana.ciornei@nxp.com> References: <20200621225451.12435-1-ioana.ciornei@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org In order to support split PCS using PHYLINK properly, we need to add a phylink_pcs_ops structure. Note that a DSA driver that wants to use these needs to implement all 4 of them: the DSA core checks the presence of these 4 function pointers in dsa_switch_ops and only then does it add a PCS to PHYLINK. This is done in order to preserve compatibility with drivers that have not yet been converted, or don't need, a split PCS setup. Also, when pcs_get_state() and pcs_an_restart() are present, their mac counterparts (mac_pcs_get_state(), mac_an_restart()) will no longer get called, as can be seen in phylink.c. Signed-off-by: Ioana Ciornei --- Changes in v3: * patch added include/net/dsa.h | 12 ++++++++++++ net/dsa/dsa_priv.h | 1 + net/dsa/port.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ net/dsa/slave.c | 6 ++++++ 4 files changed, 65 insertions(+) diff --git a/include/net/dsa.h b/include/net/dsa.h index 50389772c597..09aa36198f4b 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -446,6 +446,18 @@ struct dsa_switch_ops { bool tx_pause, bool rx_pause); void (*phylink_fixed_state)(struct dsa_switch *ds, int port, struct phylink_link_state *state); + void (*phylink_pcs_get_state)(struct dsa_switch *ds, int port, + struct phylink_link_state *state); + int (*phylink_pcs_config)(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, + const unsigned long *advertising); + void (*phylink_pcs_an_restart)(struct dsa_switch *ds, int port); + void (*phylink_pcs_link_up)(struct dsa_switch *ds, int port, + unsigned int mode, + phy_interface_t interface, int speed, + int duplex); + /* * ethtool hardware statistics. */ diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index adecf73bd608..de8e11796178 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -169,6 +169,7 @@ int dsa_port_vid_del(struct dsa_port *dp, u16 vid); int dsa_port_link_register_of(struct dsa_port *dp); void dsa_port_link_unregister_of(struct dsa_port *dp); extern const struct phylink_mac_ops dsa_port_phylink_mac_ops; +extern const struct phylink_pcs_ops dsa_port_phylink_pcs_ops; /* slave.c */ extern const struct dsa_device_ops notag_netdev_ops; diff --git a/net/dsa/port.c b/net/dsa/port.c index e23ece229c7e..a2b0460d2593 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -592,6 +592,52 @@ const struct phylink_mac_ops dsa_port_phylink_mac_ops = { .mac_link_up = dsa_port_phylink_mac_link_up, }; +static void dsa_port_pcs_get_state(struct phylink_config *config, + struct phylink_link_state *state) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + + ds->ops->phylink_pcs_get_state(ds, dp->index, state); +} + +static void dsa_port_pcs_an_restart(struct phylink_config *config) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + + ds->ops->phylink_pcs_an_restart(ds, dp->index); +} + +static int dsa_port_pcs_config(struct phylink_config *config, + unsigned int mode, phy_interface_t interface, + const unsigned long *advertising) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + + return ds->ops->phylink_pcs_config(ds, dp->index, mode, interface, + advertising); +} + +static void dsa_port_pcs_link_up(struct phylink_config *config, + unsigned int mode, phy_interface_t interface, + int speed, int duplex) +{ + struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); + struct dsa_switch *ds = dp->ds; + + ds->ops->phylink_pcs_link_up(ds, dp->index, mode, interface, speed, + duplex); +} + +const struct phylink_pcs_ops dsa_port_phylink_pcs_ops = { + .pcs_get_state = dsa_port_pcs_get_state, + .pcs_config = dsa_port_pcs_config, + .pcs_an_restart = dsa_port_pcs_an_restart, + .pcs_link_up = dsa_port_pcs_link_up, +}; + static int dsa_port_setup_phy_of(struct dsa_port *dp, bool enable) { struct dsa_switch *ds = dp->ds; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 4c7f086a047b..8856e70f6a06 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -1650,6 +1650,12 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev) if (ds->ops->get_phy_flags) phy_flags = ds->ops->get_phy_flags(ds, dp->index); + if (ds->ops->phylink_pcs_get_state && + ds->ops->phylink_pcs_an_restart && + ds->ops->phylink_pcs_config && + ds->ops->phylink_pcs_link_up) + phylink_add_pcs(dp->pl, &dsa_port_phylink_pcs_ops); + ret = phylink_of_phy_connect(dp->pl, port_dn, phy_flags); if (ret == -ENODEV && ds->slave_mii_bus) { /* We could not connect to a designated PHY or SFP, so try to From patchwork Sun Jun 21 22:54:50 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ioana Ciornei X-Patchwork-Id: 217431 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-10.0 required=3.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 67D04C433E0 for ; Sun, 21 Jun 2020 22:56:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4926C20732 for ; Sun, 21 Jun 2020 22:56:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730857AbgFUW4I (ORCPT ); Sun, 21 Jun 2020 18:56:08 -0400 Received: from inva020.nxp.com ([92.121.34.13]:36628 "EHLO inva020.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730803AbgFUW4F (ORCPT ); Sun, 21 Jun 2020 18:56:05 -0400 Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 882D81A08CA; Mon, 22 Jun 2020 00:56:02 +0200 (CEST) Received: from inva024.eu-rdc02.nxp.com (inva024.eu-rdc02.nxp.com [134.27.226.22]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 7B4CA1A08C9; Mon, 22 Jun 2020 00:56:02 +0200 (CEST) Received: from fsr-ub1864-126.ea.freescale.net (fsr-ub1864-126.ea.freescale.net [10.171.82.212]) by inva024.eu-rdc02.nxp.com (Postfix) with ESMTP id 0B31820414; Mon, 22 Jun 2020 00:56:02 +0200 (CEST) From: Ioana Ciornei To: netdev@vger.kernel.org, davem@davemloft.net Cc: vladimir.oltean@nxp.com, claudiu.manoil@nxp.com, alexandru.marginean@nxp.com, michael@walle.cc, andrew@lunn.ch, linux@armlinux.org.uk, f.fainelli@gmail.com, olteanv@gmail.com, Ioana Ciornei Subject: [PATCH net-next v3 8/9] net: dsa: felix: use resolved link config in mac_link_up() Date: Mon, 22 Jun 2020 01:54:50 +0300 Message-Id: <20200621225451.12435-9-ioana.ciornei@nxp.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200621225451.12435-1-ioana.ciornei@nxp.com> References: <20200621225451.12435-1-ioana.ciornei@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Vladimir Oltean PHYLINK now requires that parameters established through auto-negotiation be written into the MAC at the time of the mac_link_up() callback. In the case of felix, that means taking the port out of reset, setting the correct timers for PAUSE frames, and enabling/disabling TX flow control. Note that this appears to be one of those cases where git fails spectacularly: in the diff, it doesn't appear that code is moving from felix_phylink_mac_config to felix_phylink_mac_link_up. Instead, it appears as if code was moving _around_ it. Signed-off-by: Vladimir Oltean Signed-off-by: Ioana Ciornei --- Changes in v3: * patch added drivers/net/dsa/ocelot/felix.c | 83 +++++++++++++++++----------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 98ae8421ef7f..f6a7e0839bb5 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -208,6 +208,41 @@ static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port, static void felix_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int link_an_mode, const struct phylink_link_state *state) +{ + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + if (felix->info->pcs_init) + felix->info->pcs_init(ocelot, port, link_an_mode, state); +} + +static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port) +{ + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + if (felix->info->pcs_an_restart) + felix->info->pcs_an_restart(ocelot, port); +} + +static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, + unsigned int link_an_mode, + phy_interface_t interface) +{ + struct ocelot *ocelot = ds->priv; + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); + ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, + QSYS_SWITCH_PORT_MODE, port); +} + +static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, + unsigned int link_an_mode, + phy_interface_t interface, + struct phy_device *phydev, + int speed, int duplex, + bool tx_pause, bool rx_pause) { struct ocelot *ocelot = ds->priv; struct ocelot_port *ocelot_port = ocelot->ports[port]; @@ -225,7 +260,7 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), DEV_CLOCK_CFG); - switch (state->speed) { + switch (speed) { case SPEED_10: mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3); break; @@ -241,7 +276,7 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, break; default: dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", - port, state->speed); + port, speed); return; } @@ -250,7 +285,7 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, */ mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; - if (state->pause & MLO_PAUSE_TX) + if (tx_pause) mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | @@ -263,45 +298,6 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); - if (felix->info->pcs_init) - felix->info->pcs_init(ocelot, port, link_an_mode, state); - - if (felix->info->port_sched_speed_set) - felix->info->port_sched_speed_set(ocelot, port, - state->speed); -} - -static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port) -{ - struct ocelot *ocelot = ds->priv; - struct felix *felix = ocelot_to_felix(ocelot); - - if (felix->info->pcs_an_restart) - felix->info->pcs_an_restart(ocelot, port); -} - -static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, - unsigned int link_an_mode, - phy_interface_t interface) -{ - struct ocelot *ocelot = ds->priv; - struct ocelot_port *ocelot_port = ocelot->ports[port]; - - ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); - ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, - QSYS_SWITCH_PORT_MODE, port); -} - -static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, - unsigned int link_an_mode, - phy_interface_t interface, - struct phy_device *phydev, - int speed, int duplex, - bool tx_pause, bool rx_pause) -{ - struct ocelot *ocelot = ds->priv; - struct ocelot_port *ocelot_port = ocelot->ports[port]; - /* Enable MAC module */ ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); @@ -319,6 +315,9 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | QSYS_SWITCH_PORT_MODE_PORT_ENA, QSYS_SWITCH_PORT_MODE, port); + + if (felix->info->port_sched_speed_set) + felix->info->port_sched_speed_set(ocelot, port, speed); } static void felix_port_qos_map_init(struct ocelot *ocelot, int port)