From patchwork Sat Mar 14 10:15:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Russell King \(Oracle\)" X-Patchwork-Id: 222499 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=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED 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 32E75C0044D for ; Sun, 15 Mar 2020 01:30:10 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 0272220637 for ; Sun, 15 Mar 2020 01:30:10 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=armlinux.org.uk header.i=@armlinux.org.uk header.b="imzP89mH" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727114AbgCOBaI (ORCPT ); Sat, 14 Mar 2020 21:30:08 -0400 Received: from pandora.armlinux.org.uk ([78.32.30.218]:55780 "EHLO pandora.armlinux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727050AbgCOBaH (ORCPT ); Sat, 14 Mar 2020 21:30:07 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=armlinux.org.uk; s=pandora-2019; h=Date:Sender:Message-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:Subject:Cc:To:From:References: In-Reply-To:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=Wm5U3gbfur1MD53XUuCmbhwI10XWeSPv9zyJJwQg4uc=; b=imzP89mHtMp0aSEMy+Sxe8J6Uf 4LjSEsf1WHc9Kg6tGTPHxjvhvEp1EFyFFi5nJUqkJHh981nhhs335WzzkOkBeaQrSMPOh6O8TOLYj S94ttEw1CKr/3ZBafLuZV8UXnP+hHao+xQTL5SgPGUKR3s4ESMUXxcEcyUHTJYLnfW5XImtsMOrCJ g8BTLw48V2J9TPgiqbCLbc7kkHcDRs2nXsB8R9UK0RAoFA5P10OBne2f5aK+0BxQZltbyCBckvHJf QUFNZ0OtG8FJCTke+jXAX4x0yk3vUhREn8Of9mHsMNpxjQONg/i25ZnWhFxSmJ3ZDXoYdKrcwPhuz mEh0ptfA==; Received: from e0022681537dd.dyn.armlinux.org.uk ([2002:4e20:1eda:1:222:68ff:fe15:37dd]:49338 helo=rmk-PC.armlinux.org.uk) by pandora.armlinux.org.uk with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jD3pI-0006BM-Nw; Sat, 14 Mar 2020 10:15:28 +0000 Received: from rmk by rmk-PC.armlinux.org.uk with local (Exim 4.92) (envelope-from ) id 1jD3pI-0006DE-6T; Sat, 14 Mar 2020 10:15:28 +0000 In-Reply-To: <20200314101431.GF25745@shell.armlinux.org.uk> References: <20200314101431.GF25745@shell.armlinux.org.uk> From: Russell King To: Andrew Lunn , Florian Fainelli , Heiner Kallweit Cc: "David S. Miller" , netdev@vger.kernel.org, Vivien Didelot , Jakub Kicinski Subject: [PATCH net-next 1/8] net: dsa: warn if phylink_mac_link_state returns error MIME-Version: 1.0 Content-Disposition: inline Message-Id: Date: Sat, 14 Mar 2020 10:15:28 +0000 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Issue a warning to the kernel log if phylink_mac_link_state() returns an error. This should not occur, but let's make it visible. Signed-off-by: Russell King --- net/dsa/port.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/dsa/port.c b/net/dsa/port.c index e6875d8f944d..a18e65a474a5 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -457,6 +457,7 @@ static void dsa_port_phylink_mac_pcs_get_state(struct phylink_config *config, { struct dsa_port *dp = container_of(config, struct dsa_port, pl_config); struct dsa_switch *ds = dp->ds; + int err; /* Only called for inband modes */ if (!ds->ops->phylink_mac_link_state) { @@ -464,8 +465,12 @@ static void dsa_port_phylink_mac_pcs_get_state(struct phylink_config *config, return; } - if (ds->ops->phylink_mac_link_state(ds, dp->index, state) < 0) + err = ds->ops->phylink_mac_link_state(ds, dp->index, state); + if (err < 0) { + dev_err(ds->dev, "p%d: phylink_mac_link_state() failed: %d\n", + dp->index, err); state->link = 0; + } } static void dsa_port_phylink_mac_config(struct phylink_config *config, From patchwork Sat Mar 14 10:15:33 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Russell King \(Oracle\)" X-Patchwork-Id: 222496 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=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED 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 6001EC5ACBF for ; Sun, 15 Mar 2020 01:30:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 3897B2077D for ; Sun, 15 Mar 2020 01:30:37 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=armlinux.org.uk header.i=@armlinux.org.uk header.b="n/H/9AeW" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727071AbgCOBaE (ORCPT ); Sat, 14 Mar 2020 21:30:04 -0400 Received: from pandora.armlinux.org.uk ([78.32.30.218]:55780 "EHLO pandora.armlinux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726733AbgCOBaD (ORCPT ); Sat, 14 Mar 2020 21:30:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=armlinux.org.uk; s=pandora-2019; h=Date:Sender:Message-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:Subject:Cc:To:From:References: In-Reply-To:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=r2ITGOrFdkNXFEXVpBzXxFuSd3I5PbRakhCudOea2nc=; b=n/H/9AeWiCg/pmwleOrBGcjuJF FNn3f2RmqhkUNtNBXrgS2C2TbMjEZqbC2zT30K6ltYb1KNqbRlD51mKk8n8saeo0muyHzHDG8hBjE gIRduIARyI/KosHWCGUfEpDJv2QXBsnDzSvqFs+RmHxqJkiQ66zxOEbIv10/r0kEI+CNtKBkWJ9Ez YhZ7KyDqaIfbk8gPfQHpM8g3ar9UU2RQqBjxZ3Vh45DRg3CPCbQzEC8rd6vWyd9xK09DLFooL3+AM YSPyDbxUSmdE4tnStnAPfh3dN38LQQaiOcKvhfL6MP0FzFeC109fAsa/6LU1Qjqv/s363qAl6xP5q zdvw/4Tg==; Received: from e0022681537dd.dyn.armlinux.org.uk ([2001:4d48:ad52:3201:222:68ff:fe15:37dd]:41708 helo=rmk-PC.armlinux.org.uk) by pandora.armlinux.org.uk with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jD3pO-0006BW-Ai; Sat, 14 Mar 2020 10:15:34 +0000 Received: from rmk by rmk-PC.armlinux.org.uk with local (Exim 4.92) (envelope-from ) id 1jD3pN-0006DM-AA; Sat, 14 Mar 2020 10:15:33 +0000 In-Reply-To: <20200314101431.GF25745@shell.armlinux.org.uk> References: <20200314101431.GF25745@shell.armlinux.org.uk> From: Russell King To: Andrew Lunn , Florian Fainelli , Heiner Kallweit Cc: "David S. Miller" , netdev@vger.kernel.org, Vivien Didelot Subject: [PATCH net-next 2/8] net: dsa: mv88e6xxx: use BMCR definitions for serdes control register MIME-Version: 1.0 Content-Disposition: inline Message-Id: Date: Sat, 14 Mar 2020 10:15:33 +0000 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org The SGMII/1000base-X serdes register set is a clause 22 register set offset at 0x2000 in the PHYXS device. Rather than inventing our own defintions, use those that already exist, and name the register MV88E6390_SGMII_BMCR. Also remove the unused MV88E6390_SGMII_STATUS definitions. Signed-off-by: Russell King --- drivers/net/dsa/mv88e6xxx/serdes.c | 10 ++++------ drivers/net/dsa/mv88e6xxx/serdes.h | 9 +-------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 238219787233..37d7fd132f4e 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -410,20 +410,18 @@ static int mv88e6390_serdes_power_sgmii(struct mv88e6xxx_chip *chip, u8 lane, int err; err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, - MV88E6390_SGMII_CONTROL, &val); + MV88E6390_SGMII_BMCR, &val); if (err) return err; if (up) - new_val = val & ~(MV88E6390_SGMII_CONTROL_RESET | - MV88E6390_SGMII_CONTROL_LOOPBACK | - MV88E6390_SGMII_CONTROL_PDOWN); + new_val = val & ~(BMCR_RESET | BMCR_LOOPBACK | BMCR_PDOWN); else - new_val = val | MV88E6390_SGMII_CONTROL_PDOWN; + new_val = val | BMCR_PDOWN; if (val != new_val) err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, - MV88E6390_SGMII_CONTROL, new_val); + MV88E6390_SGMII_BMCR, new_val); return err; } diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index 1906b3ab29c6..15169a1cfd05 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -47,14 +47,7 @@ #define MV88E6390_PCS_CONTROL_1_PDOWN BIT(11) /* 1000BASE-X and SGMII */ -#define MV88E6390_SGMII_CONTROL 0x2000 -#define MV88E6390_SGMII_CONTROL_RESET BIT(15) -#define MV88E6390_SGMII_CONTROL_LOOPBACK BIT(14) -#define MV88E6390_SGMII_CONTROL_PDOWN BIT(11) -#define MV88E6390_SGMII_STATUS 0x2001 -#define MV88E6390_SGMII_STATUS_AN_DONE BIT(5) -#define MV88E6390_SGMII_STATUS_REMOTE_FAULT BIT(4) -#define MV88E6390_SGMII_STATUS_LINK BIT(2) +#define MV88E6390_SGMII_BMCR (0x2000 + MII_BMCR) #define MV88E6390_SGMII_INT_ENABLE 0xa001 #define MV88E6390_SGMII_INT_SPEED_CHANGE BIT(14) #define MV88E6390_SGMII_INT_DUPLEX_CHANGE BIT(13) From patchwork Sat Mar 14 10:15:43 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Russell King \(Oracle\)" X-Patchwork-Id: 222500 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=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED 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 27B72C0044D for ; Sun, 15 Mar 2020 01:29:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id CA5F620637 for ; Sun, 15 Mar 2020 01:29:58 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=armlinux.org.uk header.i=@armlinux.org.uk header.b="1Jsairvs" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727046AbgCOB35 (ORCPT ); Sat, 14 Mar 2020 21:29:57 -0400 Received: from pandora.armlinux.org.uk ([78.32.30.218]:55780 "EHLO pandora.armlinux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726916AbgCOB3z (ORCPT ); Sat, 14 Mar 2020 21:29:55 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=armlinux.org.uk; s=pandora-2019; h=Date:Sender:Message-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:Subject:Cc:To:From:References: In-Reply-To:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=E+oRIX6+3T/I17avmLhYWPWQvrTJh8YRChnpaQo4qWc=; b=1Jsairvsx4J4JMvItHTLA6mEo+ j/Rn4uWXILvoqO6BbHlxhjuIz+n8Kp1p7V2G9P1w/jvfuFV0ZRt5QC0azWTriZ4nFRIyBEzYqlOp8 rUziR+EN/+979/7QKNA65BwLaEbi9F5QqtImp1t6F31XBiJn/W3vxkXD2sVE3fbDCiklc1SdvnMq2 7K4bQBJUjTLiyVnGZgcN0sRNJS7oVJPcjmo4wLdX1JdK4bNz4ghnu/IGKJQDjfMM8QrvH8DIoI0jR L/4RYOupxUjgFraQte4r8y3bMcjRY7Zq9GncVXOJJHz+H/uNNyIsO+AepQVHDHkNfdgm0gu4zuNoW AGjV0QOw==; Received: from e0022681537dd.dyn.armlinux.org.uk ([2001:4d48:ad52:3201:222:68ff:fe15:37dd]:41712 helo=rmk-PC.armlinux.org.uk) by pandora.armlinux.org.uk with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jD3pY-0006Bm-Mv; Sat, 14 Mar 2020 10:15:44 +0000 Received: from rmk by rmk-PC.armlinux.org.uk with local (Exim 4.92) (envelope-from ) id 1jD3pX-0006Db-Hi; Sat, 14 Mar 2020 10:15:43 +0000 In-Reply-To: <20200314101431.GF25745@shell.armlinux.org.uk> References: <20200314101431.GF25745@shell.armlinux.org.uk> From: Russell King To: Andrew Lunn , Florian Fainelli , Heiner Kallweit Cc: "David S. Miller" , netdev@vger.kernel.org, Vivien Didelot Subject: [PATCH net-next 4/8] net: dsa: mv88e6xxx: extend phylink to Serdes PHYs MIME-Version: 1.0 Content-Disposition: inline Message-Id: Date: Sat, 14 Mar 2020 10:15:43 +0000 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Extend the mv88e6xxx phylink implementation down to Serdes PHYs, which handle the PCS layer of such links. - Implement phylink PCS link state reading, so that we can provide ethtool with the linkmodes and link speed in the expected manner. Note: this will only be called for in-band negotiation, which is only supported by the serdes interfaces. - Implement phylink PCS configuration, so that the in-band AN and advertisement can be configured. - Implement phylink PCS negotiation restart, so that the in-band AN can be restarted. - Implement phylink PCS link up, so that when operating out-of-band, the Serdes can be configured for the appropriate fixed speed mode. Signed-off-by: Russell King --- drivers/net/dsa/mv88e6xxx/chip.c | 174 +++++++++++++-- drivers/net/dsa/mv88e6xxx/chip.h | 14 +- drivers/net/dsa/mv88e6xxx/serdes.c | 342 ++++++++++++++++++++++++----- drivers/net/dsa/mv88e6xxx/serdes.h | 24 ++ 4 files changed, 480 insertions(+), 74 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 14a716779bc3..548a0c3edfac 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -419,9 +419,9 @@ static int mv88e6xxx_port_config_interface(struct mv88e6xxx_chip *chip, return 0; } -int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, - int speed, int duplex, int pause, - phy_interface_t mode) +static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, + int link, int speed, int duplex, int pause, + phy_interface_t mode) { struct phylink_link_state state; int err; @@ -488,6 +488,81 @@ static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) return port < chip->info->num_internal_phys; } +static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port, + struct phylink_link_state *state) +{ + struct mv88e6xxx_chip *chip = ds->priv; + u8 lane; + int err; + + mv88e6xxx_reg_lock(chip); + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane && chip->info->ops->serdes_pcs_get_state) + err = chip->info->ops->serdes_pcs_get_state(chip, port, lane, + state); + else + err = -EOPNOTSUPP; + mv88e6xxx_reg_unlock(chip); + + return err; +} + +static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, + unsigned int mode, + phy_interface_t interface, + const unsigned long *advertise) +{ + const struct mv88e6xxx_ops *ops = chip->info->ops; + u8 lane; + + if (ops->serdes_pcs_config) { + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane) + return ops->serdes_pcs_config(chip, port, lane, mode, + interface, advertise); + } + + return 0; +} + +static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port) +{ + struct mv88e6xxx_chip *chip = ds->priv; + const struct mv88e6xxx_ops *ops; + int err = 0; + u8 lane; + + ops = chip->info->ops; + + if (ops->serdes_pcs_an_restart) { + mv88e6xxx_reg_lock(chip); + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane) + err = ops->serdes_pcs_an_restart(chip, port, lane); + mv88e6xxx_reg_unlock(chip); + + if (err) + dev_err(ds->dev, "p%d: failed to restart AN\n", port); + } +} + +static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, + unsigned int mode, + int speed, int duplex) +{ + const struct mv88e6xxx_ops *ops = chip->info->ops; + u8 lane; + + if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) { + lane = mv88e6xxx_serdes_get_lane(chip, port); + if (lane) + return ops->serdes_pcs_link_up(chip, port, lane, + speed, duplex); + } + + return 0; +} + static void mv88e6065_phylink_validate(struct mv88e6xxx_chip *chip, int port, unsigned long *mask, struct phylink_link_state *state) @@ -592,22 +667,6 @@ static void mv88e6xxx_validate(struct dsa_switch *ds, int port, phylink_helper_basex_speed(state); } -static int mv88e6xxx_link_state(struct dsa_switch *ds, int port, - struct phylink_link_state *state) -{ - struct mv88e6xxx_chip *chip = ds->priv; - int err; - - mv88e6xxx_reg_lock(chip); - if (chip->info->ops->port_link_state) - err = chip->info->ops->port_link_state(chip, port, state); - else - err = -EOPNOTSUPP; - mv88e6xxx_reg_unlock(chip); - - return err; -} - static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, unsigned int mode, const struct phylink_link_state *state) @@ -629,6 +688,18 @@ static void mv88e6xxx_mac_config(struct dsa_switch *ds, int port, * gets in the way. */ err = mv88e6xxx_port_config_interface(chip, port, state->interface); + if (err && err != -EOPNOTSUPP) + goto err_unlock; + + err = mv88e6xxx_serdes_pcs_config(chip, port, mode, state->interface, + state->advertising); + /* FIXME: we should restart negotiation if something changed - which + * is something we get if we convert to using phylinks PCS operations. + */ + if (err > 0) + err = 0; + +err_unlock: mv88e6xxx_reg_unlock(chip); if (err && err != -EOPNOTSUPP) @@ -683,9 +754,14 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, /* FIXME: for an automedia port, should we force the link * down here - what if the link comes up due to "other" media * while we're bringing the port up, how is the exclusivity - * handled in the Marvell hardware? E.g. port 4 on 88E6532 + * handled in the Marvell hardware? E.g. port 2 on 88E6390 * shared between internal PHY and Serdes. */ + err = mv88e6xxx_serdes_pcs_link_up(chip, port, mode, speed, + duplex); + if (err) + goto error; + if (ops->port_set_speed) { err = ops->port_set_speed(chip, port, speed); if (err && err != -EOPNOTSUPP) @@ -3557,6 +3633,11 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6341_serdes_get_lane, + /* Check status register pause & lpa register */ + .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6390_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, .serdes_irq_enable = mv88e6390_serdes_irq_enable, .serdes_irq_status = mv88e6390_serdes_irq_status, @@ -3729,6 +3810,10 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_get_lane = mv88e6352_serdes_get_lane, + .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6352_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, .serdes_power = mv88e6352_serdes_power, .serdes_get_regs_len = mv88e6352_serdes_get_regs_len, .serdes_get_regs = mv88e6352_serdes_get_regs, @@ -3822,6 +3907,10 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_get_lane = mv88e6352_serdes_get_lane, + .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6352_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, .serdes_power = mv88e6352_serdes_power, .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, .serdes_irq_enable = mv88e6352_serdes_irq_enable, @@ -3912,6 +4001,11 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6390_serdes_get_lane, + /* Check status register pause & lpa register */ + .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6390_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, .serdes_irq_enable = mv88e6390_serdes_irq_enable, .serdes_irq_status = mv88e6390_serdes_irq_status, @@ -3968,6 +4062,11 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6390x_serdes_get_lane, + /* Check status register pause & lpa register */ + .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6390_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, .serdes_irq_enable = mv88e6390_serdes_irq_enable, .serdes_irq_status = mv88e6390_serdes_irq_status, @@ -4023,6 +4122,11 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6390_serdes_get_lane, + /* Check status register pause & lpa register */ + .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6390_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, .serdes_irq_enable = mv88e6390_serdes_irq_enable, .serdes_irq_status = mv88e6390_serdes_irq_status, @@ -4080,6 +4184,10 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_get_lane = mv88e6352_serdes_get_lane, + .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6352_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, .serdes_power = mv88e6352_serdes_power, .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, .serdes_irq_enable = mv88e6352_serdes_irq_enable, @@ -4176,6 +4284,11 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6390_serdes_get_lane, + /* Check status register pause & lpa register */ + .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6390_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, .serdes_irq_enable = mv88e6390_serdes_irq_enable, .serdes_irq_status = mv88e6390_serdes_irq_status, @@ -4319,6 +4432,11 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6341_serdes_get_lane, + /* Check status register pause & lpa register */ + .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6390_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, .serdes_irq_enable = mv88e6390_serdes_irq_enable, .serdes_irq_status = mv88e6390_serdes_irq_status, @@ -4458,6 +4576,10 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .vtu_getnext = mv88e6352_g1_vtu_getnext, .vtu_loadpurge = mv88e6352_g1_vtu_loadpurge, .serdes_get_lane = mv88e6352_serdes_get_lane, + .serdes_pcs_get_state = mv88e6352_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6352_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6352_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6352_serdes_pcs_link_up, .serdes_power = mv88e6352_serdes_power, .serdes_irq_mapping = mv88e6352_serdes_irq_mapping, .serdes_irq_enable = mv88e6352_serdes_irq_enable, @@ -4519,6 +4641,11 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6390_serdes_get_lane, + /* Check status register pause & lpa register */ + .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6390_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, .serdes_irq_enable = mv88e6390_serdes_irq_enable, .serdes_irq_status = mv88e6390_serdes_irq_status, @@ -4579,6 +4706,10 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, .serdes_power = mv88e6390_serdes_power, .serdes_get_lane = mv88e6390x_serdes_get_lane, + .serdes_pcs_get_state = mv88e6390_serdes_pcs_get_state, + .serdes_pcs_config = mv88e6390_serdes_pcs_config, + .serdes_pcs_an_restart = mv88e6390_serdes_pcs_an_restart, + .serdes_pcs_link_up = mv88e6390_serdes_pcs_link_up, .serdes_irq_mapping = mv88e6390_serdes_irq_mapping, .serdes_irq_enable = mv88e6390_serdes_irq_enable, .serdes_irq_status = mv88e6390_serdes_irq_status, @@ -5457,8 +5588,9 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .setup = mv88e6xxx_setup, .teardown = mv88e6xxx_teardown, .phylink_validate = mv88e6xxx_validate, - .phylink_mac_link_state = mv88e6xxx_link_state, + .phylink_mac_link_state = mv88e6xxx_serdes_pcs_get_state, .phylink_mac_config = mv88e6xxx_mac_config, + .phylink_mac_an_restart = mv88e6xxx_serdes_pcs_an_restart, .phylink_mac_link_down = mv88e6xxx_mac_link_down, .phylink_mac_link_up = mv88e6xxx_mac_link_up, .get_strings = mv88e6xxx_get_strings, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 851686b45414..93cc8b6a2bef 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -502,6 +502,17 @@ struct mv88e6xxx_ops { /* SERDES lane mapping */ u8 (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port); + int (*serdes_pcs_get_state)(struct mv88e6xxx_chip *chip, int port, + u8 lane, struct phylink_link_state *state); + int (*serdes_pcs_config)(struct mv88e6xxx_chip *chip, int port, + u8 lane, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertise); + int (*serdes_pcs_an_restart)(struct mv88e6xxx_chip *chip, int port, + u8 lane); + int (*serdes_pcs_link_up)(struct mv88e6xxx_chip *chip, int port, + u8 lane, int speed, int duplex); + /* SERDES interrupt handling */ unsigned int (*serdes_irq_mapping)(struct mv88e6xxx_chip *chip, int port); @@ -669,9 +680,6 @@ int mv88e6xxx_wait_mask(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask, u16 val); int mv88e6xxx_wait_bit(struct mv88e6xxx_chip *chip, int addr, int reg, int bit, int val); -int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, int link, - int speed, int duplex, int pause, - phy_interface_t mode); struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip); static inline void mv88e6xxx_reg_lock(struct mv88e6xxx_chip *chip) diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 37d7fd132f4e..6c7b031e614b 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -49,6 +49,52 @@ static int mv88e6390_serdes_write(struct mv88e6xxx_chip *chip, return mv88e6xxx_phy_write(chip, lane, reg_c45, val); } +static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, + u16 status, u16 lpa, + struct phylink_link_state *state) +{ + if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) { + state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK); + state->duplex = status & + MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ? + DUPLEX_FULL : DUPLEX_HALF; + + if (status & MV88E6390_SGMII_PHY_STATUS_TX_PAUSE) + state->pause |= MLO_PAUSE_TX; + if (status & MV88E6390_SGMII_PHY_STATUS_RX_PAUSE) + state->pause |= MLO_PAUSE_RX; + + switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) { + case MV88E6390_SGMII_PHY_STATUS_SPEED_1000: + if (state->interface == PHY_INTERFACE_MODE_2500BASEX) + state->speed = SPEED_2500; + else + state->speed = SPEED_1000; + break; + case MV88E6390_SGMII_PHY_STATUS_SPEED_100: + state->speed = SPEED_100; + break; + case MV88E6390_SGMII_PHY_STATUS_SPEED_10: + state->speed = SPEED_10; + break; + default: + dev_err(chip->dev, "invalid PHY speed\n"); + return -EINVAL; + } + } else { + state->link = false; + } + + if (state->interface == PHY_INTERFACE_MODE_2500BASEX) + mii_lpa_mod_linkmode_x(state->lp_advertising, lpa, + ETHTOOL_LINK_MODE_2500baseX_Full_BIT); + else if (state->interface == PHY_INTERFACE_MODE_1000BASEX) + mii_lpa_mod_linkmode_x(state->lp_advertising, lpa, + ETHTOOL_LINK_MODE_1000baseX_Full_BIT); + + return 0; +} + int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane, bool up) { @@ -70,6 +116,120 @@ int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane, return err; } +int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, + u8 lane, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertise) +{ + u16 adv, bmcr, val; + bool changed; + int err; + + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + adv = 0x0001; + break; + + case PHY_INTERFACE_MODE_1000BASEX: + adv = linkmode_adv_to_mii_adv_x(advertise, + ETHTOOL_LINK_MODE_1000baseX_Full_BIT); + break; + + default: + return 0; + } + + err = mv88e6352_serdes_read(chip, MII_ADVERTISE, &val); + if (err) + return err; + + changed = val != adv; + if (changed) { + err = mv88e6352_serdes_write(chip, MII_ADVERTISE, adv); + if (err) + return err; + } + + err = mv88e6352_serdes_read(chip, MII_BMCR, &val); + if (err) + return err; + + if (phylink_autoneg_inband(mode)) + bmcr = val | BMCR_ANENABLE; + else + bmcr = val & ~BMCR_ANENABLE; + + if (bmcr == val) + return changed; + + return mv88e6352_serdes_write(chip, MII_BMCR, bmcr); +} + +int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, + u8 lane, struct phylink_link_state *state) +{ + u16 lpa, status; + int err; + + err = mv88e6352_serdes_read(chip, 0x11, &status); + if (err) { + dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err); + return err; + } + + err = mv88e6352_serdes_read(chip, MII_LPA, &lpa); + if (err) { + dev_err(chip->dev, "can't read Serdes PHY LPA: %d\n", err); + return err; + } + + return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state); +} + +int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port, + u8 lane) +{ + u16 bmcr; + int err; + + err = mv88e6352_serdes_read(chip, MII_BMCR, &bmcr); + if (err) + return err; + + return mv88e6352_serdes_write(chip, MII_BMCR, bmcr | BMCR_ANRESTART); +} + +int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, + u8 lane, int speed, int duplex) +{ + u16 val, bmcr; + int err; + + err = mv88e6352_serdes_read(chip, MII_BMCR, &val); + if (err) + return err; + + bmcr = val & ~(BMCR_SPEED100 | BMCR_FULLDPLX | BMCR_SPEED1000); + switch (speed) { + case SPEED_1000: + bmcr |= BMCR_SPEED1000; + break; + case SPEED_100: + bmcr |= BMCR_SPEED100; + break; + case SPEED_10: + break; + } + + if (duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; + + if (bmcr == val) + return 0; + + return mv88e6352_serdes_write(chip, MII_BMCR, bmcr); +} + u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) { u8 cmode = chip->ports[port].cmode; @@ -538,71 +698,153 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane, return err; } -static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip, - int port, u8 lane) +int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, + u8 lane, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertise) { - u8 cmode = chip->ports[port].cmode; - struct dsa_switch *ds = chip->ds; - int duplex = DUPLEX_UNKNOWN; - int speed = SPEED_UNKNOWN; - phy_interface_t mode; - int link, err; - u16 status; + u16 val, bmcr, adv; + bool changed; + int err; + + switch (interface) { + case PHY_INTERFACE_MODE_SGMII: + adv = 0x0001; + break; + + case PHY_INTERFACE_MODE_1000BASEX: + adv = linkmode_adv_to_mii_adv_x(advertise, + ETHTOOL_LINK_MODE_1000baseX_Full_BIT); + break; + + case PHY_INTERFACE_MODE_2500BASEX: + adv = linkmode_adv_to_mii_adv_x(advertise, + ETHTOOL_LINK_MODE_2500baseX_Full_BIT); + break; + + default: + return 0; + } + + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_ADVERTISE, &val); + if (err) + return err; + + changed = val != adv; + if (changed) { + err = mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_ADVERTISE, adv); + if (err) + return err; + } + + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_BMCR, &val); + if (err) + return err; + + if (phylink_autoneg_inband(mode)) + bmcr = val | BMCR_ANENABLE; + else + bmcr = val & ~BMCR_ANENABLE; + + /* setting ANENABLE triggers a restart of negotiation */ + if (bmcr == val) + return changed; + + return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_BMCR, bmcr); +} + +int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, + u8 lane, struct phylink_link_state *state) +{ + u16 lpa, status; + int err; err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, MV88E6390_SGMII_PHY_STATUS, &status); if (err) { - dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err); - return; + dev_err(chip->dev, "can't read Serdes PHY status: %d\n", err); + return err; } - link = status & MV88E6390_SGMII_PHY_STATUS_LINK ? - LINK_FORCED_UP : LINK_FORCED_DOWN; + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_LPA, &lpa); + if (err) { + dev_err(chip->dev, "can't read Serdes PHY LPA: %d\n", err); + return err; + } - if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) { - duplex = status & MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ? - DUPLEX_FULL : DUPLEX_HALF; + return mv88e6xxx_serdes_pcs_get_state(chip, status, lpa, state); +} - switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) { - case MV88E6390_SGMII_PHY_STATUS_SPEED_1000: - if (cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) - speed = SPEED_2500; - else - speed = SPEED_1000; - break; - case MV88E6390_SGMII_PHY_STATUS_SPEED_100: - speed = SPEED_100; - break; - case MV88E6390_SGMII_PHY_STATUS_SPEED_10: - speed = SPEED_10; - break; - default: - dev_err(chip->dev, "invalid PHY speed\n"); - return; - } - } +int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port, + u8 lane) +{ + u16 bmcr; + int err; - switch (cmode) { - case MV88E6XXX_PORT_STS_CMODE_SGMII: - mode = PHY_INTERFACE_MODE_SGMII; + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_BMCR, &bmcr); + if (err) + return err; + + return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_BMCR, + bmcr | BMCR_ANRESTART); +} + +int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, + u8 lane, int speed, int duplex) +{ + u16 val, bmcr; + int err; + + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_BMCR, &val); + if (err) + return err; + + bmcr = val & ~(BMCR_SPEED100 | BMCR_FULLDPLX | BMCR_SPEED1000); + switch (speed) { + case SPEED_2500: + case SPEED_1000: + bmcr |= BMCR_SPEED1000; break; - case MV88E6XXX_PORT_STS_CMODE_1000BASEX: - mode = PHY_INTERFACE_MODE_1000BASEX; + case SPEED_100: + bmcr |= BMCR_SPEED100; break; - case MV88E6XXX_PORT_STS_CMODE_2500BASEX: - mode = PHY_INTERFACE_MODE_2500BASEX; + case SPEED_10: break; - default: - mode = PHY_INTERFACE_MODE_NA; } - err = mv88e6xxx_port_setup_mac(chip, port, link, speed, duplex, - PAUSE_OFF, mode); - if (err) - dev_err(chip->dev, "can't propagate PHY settings to MAC: %d\n", - err); - else - dsa_port_phylink_mac_change(ds, port, link == LINK_FORCED_UP); + if (duplex == DUPLEX_FULL) + bmcr |= BMCR_FULLDPLX; + + if (bmcr == val) + return 0; + + return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_BMCR, bmcr); +} + +static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip, + int port, u8 lane) +{ + u16 status; + int err; + + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_SGMII_PHY_STATUS, &status); + if (err) { + dev_err(chip->dev, "can't read SGMII PHY status: %d\n", err); + return; + } + + dsa_port_phylink_mac_change(chip->ds, port, + !!(status & MV88E6390_SGMII_PHY_STATUS_LINK)); } static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip, diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index 15169a1cfd05..a0c95322987d 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -48,6 +48,8 @@ /* 1000BASE-X and SGMII */ #define MV88E6390_SGMII_BMCR (0x2000 + MII_BMCR) +#define MV88E6390_SGMII_ADVERTISE (0x2000 + MII_ADVERTISE) +#define MV88E6390_SGMII_LPA (0x2000 + MII_LPA) #define MV88E6390_SGMII_INT_ENABLE 0xa001 #define MV88E6390_SGMII_INT_SPEED_CHANGE BIT(14) #define MV88E6390_SGMII_INT_DUPLEX_CHANGE BIT(13) @@ -66,6 +68,8 @@ #define MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL BIT(13) #define MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID BIT(11) #define MV88E6390_SGMII_PHY_STATUS_LINK BIT(10) +#define MV88E6390_SGMII_PHY_STATUS_TX_PAUSE BIT(3) +#define MV88E6390_SGMII_PHY_STATUS_RX_PAUSE BIT(2) /* Packet generator pad packet checker */ #define MV88E6390_PG_CONTROL 0xf010 @@ -75,6 +79,26 @@ u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port); +int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, + u8 lane, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertise); +int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, + u8 lane, unsigned int mode, + phy_interface_t interface, + const unsigned long *advertise); +int mv88e6352_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, + u8 lane, struct phylink_link_state *state); +int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, + u8 lane, struct phylink_link_state *state); +int mv88e6352_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port, + u8 lane); +int mv88e6390_serdes_pcs_an_restart(struct mv88e6xxx_chip *chip, int port, + u8 lane); +int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, + u8 lane, int speed, int duplex); +int mv88e6390_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, + u8 lane, int speed, int duplex); unsigned int mv88e6352_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port); unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, From patchwork Sat Mar 14 10:15:53 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Russell King \(Oracle\)" X-Patchwork-Id: 222501 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=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED 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 77680C0044D for ; Sun, 15 Mar 2020 01:29:52 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 328AA2076F for ; Sun, 15 Mar 2020 01:29:52 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=armlinux.org.uk header.i=@armlinux.org.uk header.b="HE33uxbm" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726990AbgCOB3v (ORCPT ); Sat, 14 Mar 2020 21:29:51 -0400 Received: from pandora.armlinux.org.uk ([78.32.30.218]:55780 "EHLO pandora.armlinux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726916AbgCOB3u (ORCPT ); Sat, 14 Mar 2020 21:29:50 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=armlinux.org.uk; s=pandora-2019; h=Date:Sender:Message-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:Subject:Cc:To:From:References: In-Reply-To:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=Fk+FnxOZ4piBC7QLssjdVkifsLfaxw3Fwj8s/Ji+Uas=; b=HE33uxbm4OwusDQn9X2FIOitw2 m+Q/G/2sCoAd12zShryY+f0aixAhl4eYaagNq4f42aQL20rsdswU1XJyxrrX11MLHUEMGYWHX8ZY4 /0jAKPYQV4nt12UrtzrfEPpcGwFRmMII/t3UI6fCVN03J8d2923VpqLnajkieKNf5LXcQuKI4j7wL ZYKyArMH5kqRMk69DZBJ40EqqOFFErC44G7SwrK2Ll+fzm0XONpvcD2/5YVTnnosKZyooFO/GBtr/ dq8EiBWHQR0IIl6Op6R2/FVCcHsja9KmsJQ79aLv1zy/3odgSGCcojDj159nCg/qqFJbdlGNYMy+N nBx3d48A==; Received: from e0022681537dd.dyn.armlinux.org.uk ([2001:4d48:ad52:3201:222:68ff:fe15:37dd]:41716 helo=rmk-PC.armlinux.org.uk) by pandora.armlinux.org.uk with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jD3pj-0006C4-EP; Sat, 14 Mar 2020 10:15:55 +0000 Received: from rmk by rmk-PC.armlinux.org.uk with local (Exim 4.92) (envelope-from ) id 1jD3ph-0006Dq-Pd; Sat, 14 Mar 2020 10:15:53 +0000 In-Reply-To: <20200314101431.GF25745@shell.armlinux.org.uk> References: <20200314101431.GF25745@shell.armlinux.org.uk> From: Russell King To: Andrew Lunn , Florian Fainelli , Heiner Kallweit Cc: "David S. Miller" , netdev@vger.kernel.org, Vivien Didelot Subject: [PATCH net-next 6/8] net: dsa: mv88e6xxx: combine port_set_speed and port_set_duplex MIME-Version: 1.0 Content-Disposition: inline Message-Id: Date: Sat, 14 Mar 2020 10:15:53 +0000 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Setting the speed independently of duplex makes little sense; the two parameters result from negotiation or fixed setup, and may have inter- dependencies. Moreover, they are always controlled via the same register - having them split means we have to read-modify-write this register twice. Combine the two operations into a single port_set_speed_duplex() operation. Not only is this more efficient, it reduces the size of the code as well. Signed-off-by: Russell King --- drivers/net/dsa/mv88e6xxx/chip.c | 103 ++++++++++------------------- drivers/net/dsa/mv88e6xxx/chip.h | 18 ++---- drivers/net/dsa/mv88e6xxx/port.c | 108 +++++++++++++++---------------- drivers/net/dsa/mv88e6xxx/port.h | 23 ++++--- 4 files changed, 107 insertions(+), 145 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 548a0c3edfac..34c7f3e588ec 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -452,8 +452,9 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, if (err) return err; - if (chip->info->ops->port_set_speed) { - err = chip->info->ops->port_set_speed(chip, port, speed); + if (chip->info->ops->port_set_speed_duplex) { + err = chip->info->ops->port_set_speed_duplex(chip, port, + speed, duplex); if (err && err != -EOPNOTSUPP) goto restore_link; } @@ -467,12 +468,6 @@ static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port, goto restore_link; } - if (chip->info->ops->port_set_duplex) { - err = chip->info->ops->port_set_duplex(chip, port, duplex); - if (err && err != -EOPNOTSUPP) - goto restore_link; - } - err = mv88e6xxx_port_config_interface(chip, port, mode); restore_link: if (chip->info->ops->port_set_link(chip, port, link)) @@ -762,14 +757,9 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, if (err) goto error; - if (ops->port_set_speed) { - err = ops->port_set_speed(chip, port, speed); - if (err && err != -EOPNOTSUPP) - goto error; - } - - if (ops->port_set_duplex) { - err = ops->port_set_duplex(chip, port, duplex); + if (ops->port_set_speed_duplex) { + err = ops->port_set_speed_duplex(chip, port, + speed, duplex); if (err && err != -EOPNOTSUPP) goto error; } @@ -3412,8 +3402,7 @@ static const struct mv88e6xxx_ops mv88e6085_ops = { .phy_read = mv88e6185_phy_ppu_read, .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -3452,8 +3441,7 @@ static const struct mv88e6xxx_ops mv88e6095_ops = { .phy_read = mv88e6185_phy_ppu_read, .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_set_frame_mode = mv88e6085_port_set_frame_mode, .port_set_egress_floods = mv88e6185_port_set_egress_floods, .port_set_upstream_port = mv88e6095_port_set_upstream_port, @@ -3483,8 +3471,7 @@ static const struct mv88e6xxx_ops mv88e6097_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -3523,8 +3510,7 @@ static const struct mv88e6xxx_ops mv88e6123_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_set_frame_mode = mv88e6085_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, @@ -3558,8 +3544,7 @@ static const struct mv88e6xxx_ops mv88e6131_ops = { .phy_read = mv88e6185_phy_ppu_read, .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6185_port_set_egress_floods, @@ -3601,9 +3586,8 @@ static const struct mv88e6xxx_ops mv88e6141_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6341_port_set_speed, + .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, .port_max_speed_mode = mv88e6341_port_max_speed_mode, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, @@ -3654,8 +3638,7 @@ static const struct mv88e6xxx_ops mv88e6161_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -3697,8 +3680,7 @@ static const struct mv88e6xxx_ops mv88e6165_ops = { .phy_read = mv88e6165_phy_read, .phy_write = mv88e6165_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, .port_link_state = mv88e6352_port_link_state, @@ -3733,9 +3715,8 @@ static const struct mv88e6xxx_ops mv88e6171_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -3777,9 +3758,8 @@ static const struct mv88e6xxx_ops mv88e6172_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, - .port_set_speed = mv88e6352_port_set_speed, + .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, @@ -3830,9 +3810,8 @@ static const struct mv88e6xxx_ops mv88e6175_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -3874,9 +3853,8 @@ static const struct mv88e6xxx_ops mv88e6176_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, - .port_set_speed = mv88e6352_port_set_speed, + .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, @@ -3929,8 +3907,7 @@ static const struct mv88e6xxx_ops mv88e6185_ops = { .phy_read = mv88e6185_phy_ppu_read, .phy_write = mv88e6185_phy_ppu_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_set_frame_mode = mv88e6085_port_set_frame_mode, .port_set_egress_floods = mv88e6185_port_set_egress_floods, .port_egress_rate_limiting = mv88e6095_port_egress_rate_limiting, @@ -3967,9 +3944,8 @@ static const struct mv88e6xxx_ops mv88e6190_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6390_port_set_speed, + .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, .port_max_speed_mode = mv88e6390_port_max_speed_mode, .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, @@ -4028,9 +4004,8 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6390x_port_set_speed, + .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, .port_max_speed_mode = mv88e6390x_port_max_speed_mode, .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, @@ -4089,9 +4064,8 @@ static const struct mv88e6xxx_ops mv88e6191_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6390_port_set_speed, + .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, .port_max_speed_mode = mv88e6390_port_max_speed_mode, .port_tag_remap = mv88e6390_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, @@ -4151,9 +4125,8 @@ static const struct mv88e6xxx_ops mv88e6240_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, - .port_set_speed = mv88e6352_port_set_speed, + .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, @@ -4211,9 +4184,8 @@ static const struct mv88e6xxx_ops mv88e6250_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, - .port_set_speed = mv88e6250_port_set_speed, + .port_set_speed_duplex = mv88e6250_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -4250,9 +4222,8 @@ static const struct mv88e6xxx_ops mv88e6290_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6390_port_set_speed, + .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, .port_max_speed_mode = mv88e6390_port_max_speed_mode, .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, @@ -4314,8 +4285,7 @@ static const struct mv88e6xxx_ops mv88e6320_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -4358,8 +4328,7 @@ static const struct mv88e6xxx_ops mv88e6321_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -4400,9 +4369,8 @@ static const struct mv88e6xxx_ops mv88e6341_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6341_port_set_speed, + .port_set_speed_duplex = mv88e6341_port_set_speed_duplex, .port_max_speed_mode = mv88e6341_port_max_speed_mode, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, @@ -4455,9 +4423,8 @@ static const struct mv88e6xxx_ops mv88e6350_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -4497,9 +4464,8 @@ static const struct mv88e6xxx_ops mv88e6351_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, - .port_set_speed = mv88e6185_port_set_speed, + .port_set_speed_duplex = mv88e6185_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_frame_mode = mv88e6351_port_set_frame_mode, .port_set_egress_floods = mv88e6352_port_set_egress_floods, @@ -4543,9 +4509,8 @@ static const struct mv88e6xxx_ops mv88e6352_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6352_port_set_rgmii_delay, - .port_set_speed = mv88e6352_port_set_speed, + .port_set_speed_duplex = mv88e6352_port_set_speed_duplex, .port_tag_remap = mv88e6095_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, .port_set_frame_mode = mv88e6351_port_set_frame_mode, @@ -4605,9 +4570,8 @@ static const struct mv88e6xxx_ops mv88e6390_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6390_port_set_speed, + .port_set_speed_duplex = mv88e6390_port_set_speed_duplex, .port_max_speed_mode = mv88e6390_port_max_speed_mode, .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, @@ -4670,9 +4634,8 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .phy_read = mv88e6xxx_g2_smi_phy_read, .phy_write = mv88e6xxx_g2_smi_phy_write, .port_set_link = mv88e6xxx_port_set_link, - .port_set_duplex = mv88e6xxx_port_set_duplex, .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, - .port_set_speed = mv88e6390x_port_set_speed, + .port_set_speed_duplex = mv88e6390x_port_set_speed_duplex, .port_max_speed_mode = mv88e6390x_port_max_speed_mode, .port_tag_remap = mv88e6390_port_tag_remap, .port_set_policy = mv88e6352_port_set_policy, diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 93cc8b6a2bef..72214c4bb2ab 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -399,15 +399,6 @@ struct mv88e6xxx_ops { */ int (*port_set_link)(struct mv88e6xxx_chip *chip, int port, int link); -#define DUPLEX_UNFORCED -2 - - /* Port's MAC duplex mode - * - * Use DUPLEX_HALF or DUPLEX_FULL to force half or full duplex, - * or DUPLEX_UNFORCED for normal duplex detection. - */ - int (*port_set_duplex)(struct mv88e6xxx_chip *chip, int port, int dup); - #define PAUSE_ON 1 #define PAUSE_OFF 0 @@ -417,13 +408,18 @@ struct mv88e6xxx_ops { #define SPEED_MAX INT_MAX #define SPEED_UNFORCED -2 +#define DUPLEX_UNFORCED -2 - /* Port's MAC speed (in Mbps) + /* Port's MAC speed (in Mbps) and MAC duplex mode * * Depending on the chip, 10, 100, 200, 1000, 2500, 10000 are valid. * Use SPEED_UNFORCED for normal detection, SPEED_MAX for max value. + * + * Use DUPLEX_HALF or DUPLEX_FULL to force half or full duplex, + * or DUPLEX_UNFORCED for normal duplex detection. */ - int (*port_set_speed)(struct mv88e6xxx_chip *chip, int port, int speed); + int (*port_set_speed_duplex)(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex); /* What interface mode should be used for maximum speed? */ phy_interface_t (*port_max_speed_mode)(int port); diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 0b43c650e100..442abb719cdc 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -162,46 +162,9 @@ int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link) return 0; } -int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup) -{ - u16 reg; - int err; - - err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); - if (err) - return err; - - reg &= ~(MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | - MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL); - - switch (dup) { - case DUPLEX_HALF: - reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX; - break; - case DUPLEX_FULL: - reg |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | - MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL; - break; - case DUPLEX_UNFORCED: - /* normal duplex detection */ - break; - default: - return -EOPNOTSUPP; - } - - err = mv88e6xxx_port_write(chip, port, MV88E6XXX_PORT_MAC_CTL, reg); - if (err) - return err; - - dev_dbg(chip->dev, "p%d: %s %s duplex\n", port, - reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce", - reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half"); - - return 0; -} - -static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port, - int speed, bool alt_bit, bool force_bit) +static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip, + int port, int speed, bool alt_bit, + bool force_bit, int duplex) { u16 reg, ctrl; int err; @@ -239,11 +202,29 @@ static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port, return -EOPNOTSUPP; } + switch (duplex) { + case DUPLEX_HALF: + ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX; + break; + case DUPLEX_FULL: + ctrl |= MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | + MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL; + break; + case DUPLEX_UNFORCED: + /* normal duplex detection */ + break; + default: + return -EOPNOTSUPP; + } + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_MAC_CTL, ®); if (err) return err; - reg &= ~MV88E6XXX_PORT_MAC_CTL_SPEED_MASK; + reg &= ~(MV88E6XXX_PORT_MAC_CTL_SPEED_MASK | + MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX | + MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL); + if (alt_bit) reg &= ~MV88E6390_PORT_MAC_CTL_ALTSPEED; if (force_bit) { @@ -261,12 +242,16 @@ static int mv88e6xxx_port_set_speed(struct mv88e6xxx_chip *chip, int port, dev_dbg(chip->dev, "p%d: Speed set to %d Mbps\n", port, speed); else dev_dbg(chip->dev, "p%d: Speed unforced\n", port); + dev_dbg(chip->dev, "p%d: %s %s duplex\n", port, + reg & MV88E6XXX_PORT_MAC_CTL_FORCE_DUPLEX ? "Force" : "Unforce", + reg & MV88E6XXX_PORT_MAC_CTL_DUPLEX_FULL ? "full" : "half"); return 0; } /* Support 10, 100, 200 Mbps (e.g. 88E6065 family) */ -int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) +int mv88e6065_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex) { if (speed == SPEED_MAX) speed = 200; @@ -275,11 +260,13 @@ int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) return -EOPNOTSUPP; /* Setting 200 Mbps on port 0 to 3 selects 100 Mbps */ - return mv88e6xxx_port_set_speed(chip, port, speed, false, false); + return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false, + duplex); } /* Support 10, 100, 1000 Mbps (e.g. 88E6185 family) */ -int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) +int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex) { if (speed == SPEED_MAX) speed = 1000; @@ -287,11 +274,13 @@ int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) if (speed == 200 || speed > 1000) return -EOPNOTSUPP; - return mv88e6xxx_port_set_speed(chip, port, speed, false, false); + return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false, + duplex); } /* Support 10, 100 Mbps (e.g. 88E6250 family) */ -int mv88e6250_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) +int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex) { if (speed == SPEED_MAX) speed = 100; @@ -299,11 +288,13 @@ int mv88e6250_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) if (speed > 100) return -EOPNOTSUPP; - return mv88e6xxx_port_set_speed(chip, port, speed, false, false); + return mv88e6xxx_port_set_speed_duplex(chip, port, speed, false, false, + duplex); } /* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6341) */ -int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) +int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex) { if (speed == SPEED_MAX) speed = port < 5 ? 1000 : 2500; @@ -317,7 +308,8 @@ int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) if (speed == 2500 && port < 5) return -EOPNOTSUPP; - return mv88e6xxx_port_set_speed(chip, port, speed, !port, true); + return mv88e6xxx_port_set_speed_duplex(chip, port, speed, !port, true, + duplex); } phy_interface_t mv88e6341_port_max_speed_mode(int port) @@ -329,7 +321,8 @@ phy_interface_t mv88e6341_port_max_speed_mode(int port) } /* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */ -int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) +int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex) { if (speed == SPEED_MAX) speed = 1000; @@ -340,11 +333,13 @@ int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) if (speed == 200 && port < 5) return -EOPNOTSUPP; - return mv88e6xxx_port_set_speed(chip, port, speed, true, false); + return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, false, + duplex); } /* Support 10, 100, 200, 1000, 2500 Mbps (e.g. 88E6390) */ -int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) +int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex) { if (speed == SPEED_MAX) speed = port < 9 ? 1000 : 2500; @@ -358,7 +353,8 @@ int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) if (speed == 2500 && port < 9) return -EOPNOTSUPP; - return mv88e6xxx_port_set_speed(chip, port, speed, true, true); + return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true, + duplex); } phy_interface_t mv88e6390_port_max_speed_mode(int port) @@ -370,7 +366,8 @@ phy_interface_t mv88e6390_port_max_speed_mode(int port) } /* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */ -int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) +int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex) { if (speed == SPEED_MAX) speed = port < 9 ? 1000 : 10000; @@ -381,7 +378,8 @@ int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed) if (speed >= 2500 && port < 9) return -EOPNOTSUPP; - return mv88e6xxx_port_set_speed(chip, port, speed, true, true); + return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true, + duplex); } phy_interface_t mv88e6390x_port_max_speed_mode(int port) diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 0ec4327c2b42..1d18426b7ff6 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -298,15 +298,20 @@ int mv88e6390_port_set_rgmii_delay(struct mv88e6xxx_chip *chip, int port, int mv88e6xxx_port_set_link(struct mv88e6xxx_chip *chip, int port, int link); -int mv88e6xxx_port_set_duplex(struct mv88e6xxx_chip *chip, int port, int dup); - -int mv88e6065_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); -int mv88e6185_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); -int mv88e6250_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); -int mv88e6341_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); -int mv88e6352_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); -int mv88e6390_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); -int mv88e6390x_port_set_speed(struct mv88e6xxx_chip *chip, int port, int speed); +int mv88e6065_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex); +int mv88e6185_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex); +int mv88e6250_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex); +int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex); +int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex); +int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex); +int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex); phy_interface_t mv88e6341_port_max_speed_mode(int port); phy_interface_t mv88e6390_port_max_speed_mode(int port); From patchwork Sat Mar 14 10:16:03 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Russell King \(Oracle\)" X-Patchwork-Id: 222502 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=-6.5 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED 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 5F811C1975A for ; Sun, 15 Mar 2020 01:29:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 34FC32076F for ; Sun, 15 Mar 2020 01:29:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=armlinux.org.uk header.i=@armlinux.org.uk header.b="FmyJhGMe" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726954AbgCOB3o (ORCPT ); Sat, 14 Mar 2020 21:29:44 -0400 Received: from pandora.armlinux.org.uk ([78.32.30.218]:55780 "EHLO pandora.armlinux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726932AbgCOB3m (ORCPT ); Sat, 14 Mar 2020 21:29:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=armlinux.org.uk; s=pandora-2019; h=Date:Sender:Message-Id:Content-Type: Content-Transfer-Encoding:MIME-Version:Subject:Cc:To:From:References: In-Reply-To:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help: List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=YO4Xv189fHx9vd4SXY+SLUaP901+UZkXSRafGJJ5T/c=; b=FmyJhGMePIx22PG7ejCnXizBPs UlT4ywZN0ZasqfATbViaCFXVn6XLrNVhBXnZMzrn+LLOW+/fXAadtIcxa2JSF6OrIsfd1NKReilO9 x1zGy5e70J9wMFpVgpjqacfsZ9bmnUci0MhDmymgT5X35FECay5NZGr/0dQyCwVjV0wCOkr6fnRVY guKuBfixvaKgvr1FHwW0gUUeBiXh/rsjU60tFOELyvcOPz1e5lJs9uVFdQv10RtIXVFOKdJex3aob DPpOtB7NBgINLrM6V67d8V0q0YetQty+cSrxdF+igcuspz0pxdtyY7eOFOS6CQpS9ONjk1JRngKmL RfgCZarA==; Received: from e0022681537dd.dyn.armlinux.org.uk ([fd8f:7570:feb6:1:222:68ff:fe15:37dd]:57490 helo=rmk-PC.armlinux.org.uk) by pandora.armlinux.org.uk with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.90_1) (envelope-from ) id 1jD3pt-0006CO-Gf; Sat, 14 Mar 2020 10:16:05 +0000 Received: from rmk by rmk-PC.armlinux.org.uk with local (Exim 4.92) (envelope-from ) id 1jD3pr-0006E5-WE; Sat, 14 Mar 2020 10:16:04 +0000 In-Reply-To: <20200314101431.GF25745@shell.armlinux.org.uk> References: <20200314101431.GF25745@shell.armlinux.org.uk> From: Russell King To: Andrew Lunn , Florian Fainelli , Heiner Kallweit Cc: "David S. Miller" , netdev@vger.kernel.org, Vivien Didelot Subject: [PATCH net-next 8/8] net: dsa: mv88e6xxx: use PHY_DETECT in mac_link_up/mac_link_down MIME-Version: 1.0 Content-Disposition: inline Message-Id: Date: Sat, 14 Mar 2020 10:16:03 +0000 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Use the status of the PHY_DETECT bit to determine whether we need to force the MAC settings in mac_link_up() and mac_link_down(). Signed-off-by: Russell King --- drivers/net/dsa/mv88e6xxx/chip.c | 53 +++++++++++++++++--------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 03bc15a97591..221593261e8f 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -464,6 +464,22 @@ static int mv88e6xxx_phy_is_internal(struct dsa_switch *ds, int port) return port < chip->info->num_internal_phys; } +static int mv88e6xxx_port_ppu_updates(struct mv88e6xxx_chip *chip, int port) +{ + u16 reg; + int err; + + err = mv88e6xxx_port_read(chip, port, MV88E6XXX_PORT_STS, ®); + if (err) { + dev_err(chip->dev, + "p%d: %s: failed to read port status\n", + port, __func__); + return err; + } + + return !!(reg & MV88E6XXX_PORT_STS_PHY_DETECT); +} + static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port, struct phylink_link_state *state) { @@ -692,20 +708,14 @@ static void mv88e6xxx_mac_link_down(struct dsa_switch *ds, int port, ops = chip->info->ops; - /* Internal PHYs propagate their configuration directly to the MAC. - * External PHYs depend on whether the PPU is enabled for this port. - * FIXME: we should be using the PPU enable state here. What about - * an automedia port? - */ - if (!mv88e6xxx_phy_is_internal(ds, port) && ops->port_set_link) { - mv88e6xxx_reg_lock(chip); + mv88e6xxx_reg_lock(chip); + if (!mv88e6xxx_port_ppu_updates(chip, port) && ops->port_set_link) err = ops->port_set_link(chip, port, LINK_FORCED_DOWN); - mv88e6xxx_reg_unlock(chip); + mv88e6xxx_reg_unlock(chip); - if (err) - dev_err(chip->dev, - "p%d: failed to force MAC link down\n", port); - } + if (err) + dev_err(chip->dev, + "p%d: failed to force MAC link down\n", port); } static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, @@ -720,13 +730,8 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, ops = chip->info->ops; - /* Internal PHYs propagate their configuration directly to the MAC. - * External PHYs depend on whether the PPU is enabled for this port. - * FIXME: we should be using the PPU enable state here. What about - * an automedia port? - */ - if (!mv88e6xxx_phy_is_internal(ds, port)) { - mv88e6xxx_reg_lock(chip); + mv88e6xxx_reg_lock(chip); + if (!mv88e6xxx_port_ppu_updates(chip, port)) { /* FIXME: for an automedia port, should we force the link * down here - what if the link comes up due to "other" media * while we're bringing the port up, how is the exclusivity @@ -747,13 +752,13 @@ static void mv88e6xxx_mac_link_up(struct dsa_switch *ds, int port, if (ops->port_set_link) err = ops->port_set_link(chip, port, LINK_FORCED_UP); + } error: - mv88e6xxx_reg_unlock(chip); + mv88e6xxx_reg_unlock(chip); - if (err && err != -EOPNOTSUPP) - dev_err(ds->dev, - "p%d: failed to configure MAC link up\n", port); - } + if (err && err != -EOPNOTSUPP) + dev_err(ds->dev, + "p%d: failed to configure MAC link up\n", port); } static int mv88e6xxx_stats_snapshot(struct mv88e6xxx_chip *chip, int port)