From patchwork Wed Aug 19 15:38:14 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 1347893 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=nic.cz Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=nic.cz header.i=@nic.cz header.a=rsa-sha256 header.s=default header.b=jO+UnoZ6; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BWsPT4NV9z9sRK for ; Thu, 20 Aug 2020 01:38:21 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728698AbgHSPiT (ORCPT ); Wed, 19 Aug 2020 11:38:19 -0400 Received: from lists.nic.cz ([217.31.204.67]:52266 "EHLO mail.nic.cz" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726632AbgHSPiS (ORCPT ); Wed, 19 Aug 2020 11:38:18 -0400 Received: from dellmb.labs.office.nic.cz (unknown [IPv6:2001:1488:fffe:6:8982:ed8c:62b1:c0c8]) by mail.nic.cz (Postfix) with ESMTP id 6952F140A90; Wed, 19 Aug 2020 17:38:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=nic.cz; s=default; t=1597851497; bh=kWK3OUoqmBmayQnEWbb9NlnYXxkPs4Ii3zCs8VvuC7c=; h=From:To:Date; b=jO+UnoZ6oogosVzZ84rzZ9R+RtxdpAsKpA49upbZa165NbS5NlaBjSUaZuq3HKuKn xG4YpmaytwjRSEg6Az8bvdH1Hj/YB0JOK5g4Ar+5pfy142AjPO2SbMoNlkQhKHPyUB naANZDHZblO2u8z/FukQY54bDP8tN8jBfl6u733s= From: =?utf-8?q?Marek_Beh=C3=BAn?= To: netdev@vger.kernel.org Cc: Russell King , Andrew Lunn , Florian Fainelli , Vivien Didelot , =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH net-next 1/3] net: phy: add interface mode PHY_INTERFACE_MODE_5GBASER. Date: Wed, 19 Aug 2020 17:38:14 +0200 Message-Id: <20200819153816.30834-2-marek.behun@nic.cz> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200819153816.30834-1-marek.behun@nic.cz> References: <20200819153816.30834-1-marek.behun@nic.cz> MIME-Version: 1.0 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on mail.nic.cz X-Spam-Status: No, score=0.00 X-Spamd-Bar: / X-Virus-Scanned: clamav-milter 0.102.2 at mail X-Virus-Status: Clean Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Add support for interface mode PHY_INTERFACE_MODE_5GBASER. Signed-off-by: Marek Behún --- include/linux/phy.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/linux/phy.h b/include/linux/phy.h index 3a09d2bf69ea4..0214d70e12a69 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -105,6 +105,7 @@ typedef enum { PHY_INTERFACE_MODE_TRGMII, PHY_INTERFACE_MODE_1000BASEX, PHY_INTERFACE_MODE_2500BASEX, + PHY_INTERFACE_MODE_5GBASER, PHY_INTERFACE_MODE_RXAUI, PHY_INTERFACE_MODE_XAUI, /* 10GBASE-R, XFI, SFI - single lane 10G Serdes */ @@ -183,6 +184,8 @@ static inline const char *phy_modes(phy_interface_t interface) return "1000base-x"; case PHY_INTERFACE_MODE_2500BASEX: return "2500base-x"; + case PHY_INTERFACE_MODE_5GBASER: + return "5gbase-r"; case PHY_INTERFACE_MODE_RXAUI: return "rxaui"; case PHY_INTERFACE_MODE_XAUI: From patchwork Wed Aug 19 15:38:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 1347894 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=nic.cz Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=nic.cz header.i=@nic.cz header.a=rsa-sha256 header.s=default header.b=jq9IWh2u; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BWsPd22Rtz9sPB for ; Thu, 20 Aug 2020 01:38:29 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728765AbgHSPi1 (ORCPT ); Wed, 19 Aug 2020 11:38:27 -0400 Received: from lists.nic.cz ([217.31.204.67]:52276 "EHLO mail.nic.cz" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726794AbgHSPiU (ORCPT ); Wed, 19 Aug 2020 11:38:20 -0400 Received: from dellmb.labs.office.nic.cz (unknown [IPv6:2001:1488:fffe:6:8982:ed8c:62b1:c0c8]) by mail.nic.cz (Postfix) with ESMTP id 8AF44140A94; Wed, 19 Aug 2020 17:38:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=nic.cz; s=default; t=1597851497; bh=mQ+Lb3nWO9UHY/hUdWAvXj0UsmEjHd7oDjKnulbnSIg=; h=From:To:Date; b=jq9IWh2u4X3g7/Xykqbhf7Y+C+hf5UlPAhOq8xHxqVB0BVCCRjL3ZiTuLV5hKqMT4 s/SXz01C0NdrWF2j2JBuocPfF2IjiYHWQHk4gFDFq74nYR4UWi9kLsRLq7cn/gbIOr 40n0M7/nKT1ICk7hPNWSlSiXVhsO7qujFhuQ/o4o= From: =?utf-8?q?Marek_Beh=C3=BAn?= To: netdev@vger.kernel.org Cc: Russell King , Andrew Lunn , Florian Fainelli , Vivien Didelot , =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH net-next 2/3] net: dsa: mv88e6xxx: return error instead of lane in .serdes_get_lane Date: Wed, 19 Aug 2020 17:38:15 +0200 Message-Id: <20200819153816.30834-3-marek.behun@nic.cz> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200819153816.30834-1-marek.behun@nic.cz> References: <20200819153816.30834-1-marek.behun@nic.cz> MIME-Version: 1.0 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on mail.nic.cz X-Spam-Status: No, score=0.00 X-Spamd-Bar: / X-Virus-Scanned: clamav-milter 0.102.2 at mail X-Virus-Status: Clean Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org Currently the .serdes_get_lane method gets the lane as the result of the method, returning 0 if no SERDES is on given port. This was okay till now, because on no mv88e6xxx switch were it possible to have SERDES on port/lane 0. But it becomes incompatible with 88E6393X, on which the SERDES ports are ports 0, 9 and 10 with lanes 0, 9 and 10, respectively. This patch therefore changes the .serdes_get_lane method API so that it returns 0 on success (if a lane is found) and -ENODEV otherwise. The lane itself is stored into a place pointed to by a parameter. Signed-off-by: Marek Behún Reported-by: kernel test robot Reported-by: kernel test robot Reported-by: Dan Carpenter --- drivers/net/dsa/mv88e6xxx/chip.c | 33 +++++++------ drivers/net/dsa/mv88e6xxx/chip.h | 2 +- drivers/net/dsa/mv88e6xxx/port.c | 10 ++-- drivers/net/dsa/mv88e6xxx/serdes.c | 78 +++++++++++++++--------------- drivers/net/dsa/mv88e6xxx/serdes.h | 16 +++--- 5 files changed, 72 insertions(+), 67 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 7a71c9902e73e..0a5e2740a79db 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -487,13 +487,14 @@ static int mv88e6xxx_serdes_pcs_get_state(struct dsa_switch *ds, int port, u8 lane; int err; + if (!chip->info->ops->serdes_pcs_get_state) + return -EOPNOTSUPP; + mv88e6xxx_reg_lock(chip); - lane = mv88e6xxx_serdes_get_lane(chip, port); - if (lane && chip->info->ops->serdes_pcs_get_state) + err = mv88e6xxx_serdes_get_lane(chip, port, &lane); + if (!err) err = chip->info->ops->serdes_pcs_get_state(chip, port, lane, state); - else - err = -EOPNOTSUPP; mv88e6xxx_reg_unlock(chip); return err; @@ -505,11 +506,12 @@ static int mv88e6xxx_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, const unsigned long *advertise) { const struct mv88e6xxx_ops *ops = chip->info->ops; + int err; u8 lane; if (ops->serdes_pcs_config) { - lane = mv88e6xxx_serdes_get_lane(chip, port); - if (lane) + err = mv88e6xxx_serdes_get_lane(chip, port, &lane); + if (!err) return ops->serdes_pcs_config(chip, port, lane, mode, interface, advertise); } @@ -528,8 +530,8 @@ static void mv88e6xxx_serdes_pcs_an_restart(struct dsa_switch *ds, int port) if (ops->serdes_pcs_an_restart) { mv88e6xxx_reg_lock(chip); - lane = mv88e6xxx_serdes_get_lane(chip, port); - if (lane) + err = mv88e6xxx_serdes_get_lane(chip, port, &lane); + if (!err) err = ops->serdes_pcs_an_restart(chip, port, lane); mv88e6xxx_reg_unlock(chip); @@ -543,11 +545,12 @@ static int mv88e6xxx_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, int speed, int duplex) { const struct mv88e6xxx_ops *ops = chip->info->ops; + int err; u8 lane; if (!phylink_autoneg_inband(mode) && ops->serdes_pcs_link_up) { - lane = mv88e6xxx_serdes_get_lane(chip, port); - if (lane) + err = mv88e6xxx_serdes_get_lane(chip, port, &lane); + if (!err) return ops->serdes_pcs_link_up(chip, port, lane, speed, duplex); } @@ -2423,12 +2426,12 @@ static irqreturn_t mv88e6xxx_serdes_irq_thread_fn(int irq, void *dev_id) struct mv88e6xxx_port *mvp = dev_id; struct mv88e6xxx_chip *chip = mvp->chip; irqreturn_t ret = IRQ_NONE; - int port = mvp->port; + int port = mvp->port, err; u8 lane; mv88e6xxx_reg_lock(chip); - lane = mv88e6xxx_serdes_get_lane(chip, port); - if (lane) + err = mv88e6xxx_serdes_get_lane(chip, port, &lane); + if (!err) ret = mv88e6xxx_serdes_irq_status(chip, port, lane); mv88e6xxx_reg_unlock(chip); @@ -2493,8 +2496,8 @@ static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane; int err; - lane = mv88e6xxx_serdes_get_lane(chip, port); - if (!lane) + err = mv88e6xxx_serdes_get_lane(chip, port, &lane); + if (err) return 0; if (on) { diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index 823ae89e5fcac..cc23810438dfe 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -494,7 +494,7 @@ struct mv88e6xxx_ops { bool up); /* SERDES lane mapping */ - u8 (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port); + int (*serdes_get_lane)(struct mv88e6xxx_chip *chip, int port, u8 *lane); int (*serdes_pcs_get_state)(struct mv88e6xxx_chip *chip, int port, u8 lane, struct phylink_link_state *state); diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 8128dc607cf46..9d5189f2474ce 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -429,8 +429,8 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, if (cmode == chip->ports[port].cmode && !force) return 0; - lane = mv88e6xxx_serdes_get_lane(chip, port); - if (lane) { + err = mv88e6xxx_serdes_get_lane(chip, port, &lane); + if (!err) { if (chip->ports[port].serdes_irq) { err = mv88e6xxx_serdes_irq_disable(chip, port, lane); if (err) @@ -458,9 +458,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, chip->ports[port].cmode = cmode; - lane = mv88e6xxx_serdes_get_lane(chip, port); - if (!lane) - return -ENODEV; + err = mv88e6xxx_serdes_get_lane(chip, port, &lane); + if (err) + return err; err = mv88e6xxx_serdes_power_up(chip, port, lane); if (err) diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 9c07b4f3d3454..9074d1097b614 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -230,25 +230,25 @@ int mv88e6352_serdes_pcs_link_up(struct mv88e6xxx_chip *chip, int port, return mv88e6352_serdes_write(chip, MII_BMCR, bmcr); } -u8 mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) +int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane) { u8 cmode = chip->ports[port].cmode; - u8 lane = 0; if ((cmode == MV88E6XXX_PORT_STS_CMODE_100BASEX) || (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX) || - (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)) - lane = 0xff; /* Unused */ + (cmode == MV88E6XXX_PORT_STS_CMODE_SGMII)) { + *lane = 0xff; /* Unused */ + return 0; + } - return lane; + return -ENODEV; } static bool mv88e6352_port_has_serdes(struct mv88e6xxx_chip *chip, int port) { - if (mv88e6xxx_serdes_get_lane(chip, port)) - return true; + u8 lane; - return false; + return !mv88e6xxx_serdes_get_lane(chip, port, &lane); } struct mv88e6352_serdes_hw_stat { @@ -411,60 +411,60 @@ void mv88e6352_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) } } -u8 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) +int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane) { u8 cmode = chip->ports[port].cmode; - u8 lane = 0; + *lane = -1; switch (port) { case 5: if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) - lane = MV88E6341_PORT5_LANE; + *lane = MV88E6341_PORT5_LANE; break; } - return lane; + return *lane == -1 ? -ENODEV : 0; } -u8 mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) +int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane) { u8 cmode = chip->ports[port].cmode; - u8 lane = 0; + *lane = -1; switch (port) { case 9: if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) - lane = MV88E6390_PORT9_LANE0; + *lane = MV88E6390_PORT9_LANE0; break; case 10: if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX) - lane = MV88E6390_PORT10_LANE0; + *lane = MV88E6390_PORT10_LANE0; break; } - return lane; + return *lane == -1 ? -ENODEV : 0; } -u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) +int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane) { u8 cmode_port = chip->ports[port].cmode; u8 cmode_port10 = chip->ports[10].cmode; u8 cmode_port9 = chip->ports[9].cmode; - u8 lane = 0; + *lane = -1; switch (port) { case 2: if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) - lane = MV88E6390_PORT9_LANE1; + *lane = MV88E6390_PORT9_LANE1; break; case 3: if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || @@ -472,7 +472,7 @@ u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) - lane = MV88E6390_PORT9_LANE2; + *lane = MV88E6390_PORT9_LANE2; break; case 4: if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || @@ -480,14 +480,14 @@ u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) - lane = MV88E6390_PORT9_LANE3; + *lane = MV88E6390_PORT9_LANE3; break; case 5: if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_SGMII || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) - lane = MV88E6390_PORT10_LANE1; + *lane = MV88E6390_PORT10_LANE1; break; case 6: if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || @@ -495,7 +495,7 @@ u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) - lane = MV88E6390_PORT10_LANE2; + *lane = MV88E6390_PORT10_LANE2; break; case 7: if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || @@ -503,7 +503,7 @@ u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) if (cmode_port == MV88E6XXX_PORT_STS_CMODE_1000BASEX) - lane = MV88E6390_PORT10_LANE3; + *lane = MV88E6390_PORT10_LANE3; break; case 9: if (cmode_port9 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || @@ -511,7 +511,7 @@ u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) cmode_port9 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_XAUI || cmode_port9 == MV88E6XXX_PORT_STS_CMODE_RXAUI) - lane = MV88E6390_PORT9_LANE0; + *lane = MV88E6390_PORT9_LANE0; break; case 10: if (cmode_port10 == MV88E6XXX_PORT_STS_CMODE_1000BASEX || @@ -519,11 +519,11 @@ u8 mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port) cmode_port10 == MV88E6XXX_PORT_STS_CMODE_2500BASEX || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_XAUI || cmode_port10 == MV88E6XXX_PORT_STS_CMODE_RXAUI) - lane = MV88E6390_PORT10_LANE0; + *lane = MV88E6390_PORT10_LANE0; break; } - return lane; + return *lane == -1 ? -ENODEV : 0; } /* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */ @@ -532,7 +532,6 @@ static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane, { u16 val, new_val; int err; - err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, MV88E6390_10G_CTRL1, &val); @@ -590,7 +589,9 @@ static struct mv88e6390_serdes_hw_stat mv88e6390_serdes_hw_stats[] = { int mv88e6390_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port) { - if (mv88e6390_serdes_get_lane(chip, port) == 0) + u8 lane; + + if (mv88e6390_serdes_get_lane(chip, port, &lane)) return 0; return ARRAY_SIZE(mv88e6390_serdes_hw_stats); @@ -600,9 +601,10 @@ int mv88e6390_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, uint8_t *data) { struct mv88e6390_serdes_hw_stat *stat; + u8 lane; int i; - if (mv88e6390_serdes_get_lane(chip, port) == 0) + if (mv88e6390_serdes_get_lane(chip, port, &lane)) return 0; for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { @@ -635,11 +637,10 @@ int mv88e6390_serdes_get_stats(struct mv88e6xxx_chip *chip, int port, uint64_t *data) { struct mv88e6390_serdes_hw_stat *stat; - int lane; + u8 lane; int i; - lane = mv88e6390_serdes_get_lane(chip, port); - if (lane == 0) + if (mv88e6390_serdes_get_lane(chip, port, &lane)) return 0; for (i = 0; i < ARRAY_SIZE(mv88e6390_serdes_hw_stats); i++) { @@ -976,7 +977,9 @@ static const u16 mv88e6390_serdes_regs[] = { int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port) { - if (mv88e6xxx_serdes_get_lane(chip, port) == 0) + u8 lane; + + if (mv88e6xxx_serdes_get_lane(chip, port, &lane)) return 0; return ARRAY_SIZE(mv88e6390_serdes_regs) * sizeof(u16); @@ -985,12 +988,11 @@ int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port) void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p) { u16 *p = _p; - int lane; u16 reg; + u8 lane; int i; - lane = mv88e6xxx_serdes_get_lane(chip, port); - if (lane == 0) + if (mv88e6xxx_serdes_get_lane(chip, port, &lane)) return; for (i = 0 ; i < ARRAY_SIZE(mv88e6390_serdes_regs); i++) { diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index 14315f26228a3..95d04dab8d251 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -73,10 +73,10 @@ #define MV88E6390_PG_CONTROL 0xf010 #define MV88E6390_PG_CONTROL_ENABLE_PC BIT(0) -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 mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); +int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); +int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); +int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, u8 lane, unsigned int mode, phy_interface_t interface, @@ -130,13 +130,13 @@ int mv88e6390_serdes_get_regs_len(struct mv88e6xxx_chip *chip, int port); void mv88e6390_serdes_get_regs(struct mv88e6xxx_chip *chip, int port, void *_p); /* Return the (first) SERDES lane address a port is using, 0 otherwise. */ -static inline u8 mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip, - int port) +static inline int mv88e6xxx_serdes_get_lane(struct mv88e6xxx_chip *chip, + int port, u8 *lane) { if (!chip->info->ops->serdes_get_lane) - return 0; + return -EOPNOTSUPP; - return chip->info->ops->serdes_get_lane(chip, port); + return chip->info->ops->serdes_get_lane(chip, port, lane); } static inline int mv88e6xxx_serdes_power_up(struct mv88e6xxx_chip *chip, From patchwork Wed Aug 19 15:38:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Marek_Beh=C3=BAn?= X-Patchwork-Id: 1347896 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=23.128.96.18; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=nic.cz Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=nic.cz header.i=@nic.cz header.a=rsa-sha256 header.s=default header.b=l3HcMD0T; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by ozlabs.org (Postfix) with ESMTP id 4BWsQG2dzMz9sTW for ; Thu, 20 Aug 2020 01:39:02 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728813AbgHSPi7 (ORCPT ); Wed, 19 Aug 2020 11:38:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:32928 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728699AbgHSPiW (ORCPT ); Wed, 19 Aug 2020 11:38:22 -0400 Received: from mail.nic.cz (mail.nic.cz [IPv6:2001:1488:800:400::400]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 92CE3C061383 for ; Wed, 19 Aug 2020 08:38:21 -0700 (PDT) Received: from dellmb.labs.office.nic.cz (unknown [IPv6:2001:1488:fffe:6:8982:ed8c:62b1:c0c8]) by mail.nic.cz (Postfix) with ESMTP id B8AF7140A99; Wed, 19 Aug 2020 17:38:17 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=nic.cz; s=default; t=1597851497; bh=xj1eswhaxDPAvqfcGRhLYBAKnnnxPSOk7jult7LQ5Ws=; h=From:To:Date; b=l3HcMD0TtrkUha9YK2/gq9m7z24n2k1xOl3eexrFTKNELnbWZB+Lzc5Gs6G4nseKu T6n5xsu3DLgnHL5HuOVgmJ3IuUMqYeM2nBvqiKTp7JmDHrSm/7WAKm4dhjB6VhKZk7 9HEKCJHPnjImS/aWoA1cnotOCn4B5jjcLC/fkwqA= From: =?utf-8?q?Marek_Beh=C3=BAn?= To: netdev@vger.kernel.org Cc: Russell King , Andrew Lunn , Florian Fainelli , Vivien Didelot , =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH net-next 3/3] net: dsa: mv88e6xxx: add support for 88E6393X from Amethyst family Date: Wed, 19 Aug 2020 17:38:16 +0200 Message-Id: <20200819153816.30834-4-marek.behun@nic.cz> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200819153816.30834-1-marek.behun@nic.cz> References: <20200819153816.30834-1-marek.behun@nic.cz> MIME-Version: 1.0 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on mail.nic.cz X-Spam-Status: No, score=0.00 X-Spamd-Bar: / X-Virus-Scanned: clamav-milter 0.102.2 at mail X-Virus-Status: Clean Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org This adds support for 88E6393X, which differs from Peridot (6390 family) in that instead of XAUI and RXAUI it supports 5GBASE-R, 10GBASE-R and USXGMII modes and these modes are supported on ports 0, 9 and 10. The USXGMII is not supported yet, since I couldn't find information about the corresponding PHY registers. The SERDES stats counters are not implemented, because they work differently from Peridot and I couldn't get them to work. The SERDES register dumps are not implemented. Signed-off-by: Marek Behún --- drivers/net/dsa/mv88e6xxx/chip.c | 97 ++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx/chip.h | 4 +- drivers/net/dsa/mv88e6xxx/port.c | 77 +++++++++++++++++- drivers/net/dsa/mv88e6xxx/port.h | 9 +++ drivers/net/dsa/mv88e6xxx/serdes.c | 126 ++++++++++++++++++++++++++++- drivers/net/dsa/mv88e6xxx/serdes.h | 8 ++ 6 files changed, 314 insertions(+), 7 deletions(-) diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 0a5e2740a79db..d97b898312e20 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -637,6 +637,21 @@ static void mv88e6390x_phylink_validate(struct mv88e6xxx_chip *chip, int port, mv88e6390_phylink_validate(chip, port, mask, state); } +static void mv88e6393x_phylink_validate(struct mv88e6xxx_chip *chip, int port, + unsigned long *mask, + struct phylink_link_state *state) +{ + if (port == 0 || port == 9 || port == 10) { + phylink_set(mask, 2500baseX_Full); + phylink_set(mask, 2500baseT_Full); + phylink_set(mask, 5000baseT_Full); + phylink_set(mask, 10000baseT_Full); + phylink_set(mask, 10000baseKR_Full); + } + + mv88e6390_phylink_validate(chip, port, mask, state); +} + static void mv88e6xxx_validate(struct dsa_switch *ds, int port, unsigned long *supported, struct phylink_link_state *state) @@ -4705,6 +4720,63 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = { .phylink_validate = mv88e6390x_phylink_validate, }; +static const struct mv88e6xxx_ops mv88e6393x_ops = { + /* MV88E6XXX_FAMILY_6393 */ + .setup_errata = mv88e6390_setup_errata, + .irl_init_all = mv88e6390_g2_irl_init_all, + .get_eeprom = mv88e6xxx_g2_get_eeprom8, + .set_eeprom = mv88e6xxx_g2_set_eeprom8, + .set_switch_mac = mv88e6xxx_g2_set_switch_mac, + .phy_read = mv88e6xxx_g2_smi_phy_read, + .phy_write = mv88e6xxx_g2_smi_phy_write, + .port_set_link = mv88e6xxx_port_set_link, + .port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay, + .port_set_speed_duplex = mv88e6393x_port_set_speed_duplex, + .port_max_speed_mode = mv88e6393x_port_max_speed_mode, + .port_tag_remap = mv88e6390_port_tag_remap, + .port_set_policy = mv88e6352_port_set_policy, + .port_set_frame_mode = mv88e6351_port_set_frame_mode, + .port_set_egress_floods = mv88e6352_port_set_egress_floods, + .port_set_ether_type = mv88e6351_port_set_ether_type, + .port_set_jumbo_size = mv88e6165_port_set_jumbo_size, + .port_egress_rate_limiting = mv88e6097_port_egress_rate_limiting, + .port_pause_limit = mv88e6390_port_pause_limit, + .port_disable_learn_limit = mv88e6xxx_port_disable_learn_limit, + .port_disable_pri_override = mv88e6xxx_port_disable_pri_override, + .port_get_cmode = mv88e6352_port_get_cmode, + .port_set_cmode = mv88e6393x_port_set_cmode, + .port_setup_message_port = mv88e6xxx_setup_message_port, + .stats_snapshot = mv88e6390_g1_stats_snapshot, + .stats_set_histogram = mv88e6390_g1_stats_set_histogram, + .stats_get_sset_count = mv88e6320_stats_get_sset_count, + .stats_get_strings = mv88e6320_stats_get_strings, + .stats_get_stats = mv88e6390_stats_get_stats, + .set_cpu_port = mv88e6390_g1_set_cpu_port, + .set_egress_port = mv88e6390_g1_set_egress_port, + .watchdog_ops = &mv88e6390_watchdog_ops, + .mgmt_rsvd2cpu = mv88e6390_g1_mgmt_rsvd2cpu, + .pot_clear = mv88e6xxx_g2_pot_clear, + .reset = mv88e6352_g1_reset, + .rmu_disable = mv88e6390_g1_rmu_disable, + .atu_get_hash = mv88e6165_g1_atu_get_hash, + .atu_set_hash = mv88e6165_g1_atu_set_hash, + .vtu_getnext = mv88e6390_g1_vtu_getnext, + .vtu_loadpurge = mv88e6390_g1_vtu_loadpurge, + .serdes_power = mv88e6390_serdes_power, + .serdes_get_lane = mv88e6393x_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 = mv88e6393x_serdes_irq_enable, + .serdes_irq_status = mv88e6393x_serdes_irq_status, + .gpio_ops = &mv88e6352_gpio_ops, + .avb_ops = &mv88e6390_avb_ops, + .ptp_ops = &mv88e6352_ptp_ops, + .phylink_validate = mv88e6393x_phylink_validate, +}; + static const struct mv88e6xxx_info mv88e6xxx_table[] = { [MV88E6085] = { .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6085, @@ -5366,6 +5438,31 @@ static const struct mv88e6xxx_info mv88e6xxx_table[] = { .ptp_support = true, .ops = &mv88e6390x_ops, }, + + [MV88E6393X] = { + .prod_num = MV88E6XXX_PORT_SWITCH_ID_PROD_6393X, + .family = MV88E6XXX_FAMILY_6393, + .name = "Marvell 88E6393X", + .num_databases = 4096, + .num_macs = 16384, + .num_ports = 11, /* 10 + Z80 */ + .num_internal_phys = 9, + .num_gpio = 16, + .max_vid = 8191, + .port_base_addr = 0x0, + .phy_base_addr = 0x0, + .global1_addr = 0x1b, + .global2_addr = 0x1c, + .age_time_coeff = 3750, + .g1_irqs = 9, + .g2_irqs = 14, + .atu_move_port_mask = 0x1f, + .pvt = true, + .multi_chip = true, + .tag_protocol = DSA_TAG_PROTO_DSA, + .ptp_support = true, + .ops = &mv88e6393x_ops, + }, }; static const struct mv88e6xxx_info *mv88e6xxx_lookup_info(unsigned int prod_num) diff --git a/drivers/net/dsa/mv88e6xxx/chip.h b/drivers/net/dsa/mv88e6xxx/chip.h index cc23810438dfe..9b36c7a21365b 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.h +++ b/drivers/net/dsa/mv88e6xxx/chip.h @@ -75,6 +75,7 @@ enum mv88e6xxx_model { MV88E6352, MV88E6390, MV88E6390X, + MV88E6393X, }; enum mv88e6xxx_family { @@ -89,7 +90,8 @@ enum mv88e6xxx_family { MV88E6XXX_FAMILY_6341, /* 6141 6341 */ MV88E6XXX_FAMILY_6351, /* 6171 6175 6350 6351 */ MV88E6XXX_FAMILY_6352, /* 6172 6176 6240 6352 */ - MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */ + MV88E6XXX_FAMILY_6390, /* 6190 6190X 6191 6290 6390 6390X */ + MV88E6XXX_FAMILY_6393, /* 6393X */ }; struct mv88e6xxx_ops; diff --git a/drivers/net/dsa/mv88e6xxx/port.c b/drivers/net/dsa/mv88e6xxx/port.c index 9d5189f2474ce..8e974bc1b858e 100644 --- a/drivers/net/dsa/mv88e6xxx/port.c +++ b/drivers/net/dsa/mv88e6xxx/port.c @@ -187,11 +187,16 @@ static int mv88e6xxx_port_set_speed_duplex(struct mv88e6xxx_chip *chip, ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000; break; case 2500: - if (alt_bit) - ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 | - MV88E6390_PORT_MAC_CTL_ALTSPEED; + if (chip->info->family == MV88E6XXX_FAMILY_6393) + ctrl = MV88E6XXX_PORT_MAC_CTL_SPEED_1000; else ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000; + if (alt_bit) + ctrl |= MV88E6390_PORT_MAC_CTL_ALTSPEED; + break; + case 5000: + ctrl = MV88E6390_PORT_MAC_CTL_SPEED_10000 | + MV88E6390_PORT_MAC_CTL_ALTSPEED; break; case 10000: /* all bits set, fall through... */ @@ -390,6 +395,31 @@ phy_interface_t mv88e6390x_port_max_speed_mode(int port) return PHY_INTERFACE_MODE_NA; } +/* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X) */ +int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port, + int speed, int duplex) +{ + if (speed == SPEED_MAX) + speed = (port > 0 && port < 9) ? 1000 : 10000; + + if (speed == 200 && port != 0) + return -EOPNOTSUPP; + + if (speed >= 2500 && (port > 0 && port < 9)) + return -EOPNOTSUPP; + + return mv88e6xxx_port_set_speed_duplex(chip, port, speed, true, true, + duplex); +} + +phy_interface_t mv88e6393x_port_max_speed_mode(int port) +{ + if (port == 0 || port == 9 || port == 10) + return PHY_INTERFACE_MODE_10GBASER; + + return PHY_INTERFACE_MODE_NA; +} + static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, phy_interface_t mode, bool force) { @@ -414,6 +444,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, case PHY_INTERFACE_MODE_2500BASEX: cmode = MV88E6XXX_PORT_STS_CMODE_2500BASEX; break; + case PHY_INTERFACE_MODE_5GBASER: + cmode = MV88E6393_PORT_STS_CMODE_5GBASER; + break; case PHY_INTERFACE_MODE_XGMII: case PHY_INTERFACE_MODE_XAUI: cmode = MV88E6XXX_PORT_STS_CMODE_XAUI; @@ -421,6 +454,9 @@ static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port, case PHY_INTERFACE_MODE_RXAUI: cmode = MV88E6XXX_PORT_STS_CMODE_RXAUI; break; + case PHY_INTERFACE_MODE_10GBASER: + cmode = MV88E6393_PORT_STS_CMODE_10GBASER; + break; default: cmode = 0; } @@ -482,6 +518,15 @@ int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, if (port != 9 && port != 10) return -EOPNOTSUPP; + switch (mode) { + case PHY_INTERFACE_MODE_5GBASER: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_USXGMII: + return -EINVAL; + default: + break; + } + return mv88e6xxx_port_set_cmode(chip, port, mode, false); } @@ -491,6 +536,29 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port, if (port != 9 && port != 10) return -EOPNOTSUPP; + switch (mode) { + case PHY_INTERFACE_MODE_NA: + return 0; + case PHY_INTERFACE_MODE_5GBASER: + case PHY_INTERFACE_MODE_XGMII: + case PHY_INTERFACE_MODE_XAUI: + case PHY_INTERFACE_MODE_RXAUI: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_USXGMII: + return -EINVAL; + default: + break; + } + + return mv88e6xxx_port_set_cmode(chip, port, mode, false); +} + +int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, + phy_interface_t mode) +{ + if (port != 9 && port != 10) + return -EOPNOTSUPP; + switch (mode) { case PHY_INTERFACE_MODE_NA: return 0; @@ -541,9 +609,12 @@ int mv88e6341_port_set_cmode(struct mv88e6xxx_chip *chip, int port, switch (mode) { case PHY_INTERFACE_MODE_NA: return 0; + case PHY_INTERFACE_MODE_5GBASER: case PHY_INTERFACE_MODE_XGMII: case PHY_INTERFACE_MODE_XAUI: case PHY_INTERFACE_MODE_RXAUI: + case PHY_INTERFACE_MODE_10GBASER: + case PHY_INTERFACE_MODE_USXGMII: return -EINVAL; default: break; diff --git a/drivers/net/dsa/mv88e6xxx/port.h b/drivers/net/dsa/mv88e6xxx/port.h index 44d76ac973f62..040b691b07eff 100644 --- a/drivers/net/dsa/mv88e6xxx/port.h +++ b/drivers/net/dsa/mv88e6xxx/port.h @@ -59,6 +59,9 @@ #define MV88E6185_PORT_STS_CMODE_1000BASE_X 0x0005 #define MV88E6185_PORT_STS_CMODE_PHY 0x0006 #define MV88E6185_PORT_STS_CMODE_DISABLED 0x0007 +#define MV88E6393_PORT_STS_CMODE_5GBASER 0x000c +#define MV88E6393_PORT_STS_CMODE_10GBASER 0x000d +#define MV88E6393_PORT_STS_CMODE_USXGMII 0x000e /* Offset 0x01: MAC (or PCS or Physical) Control Register */ #define MV88E6XXX_PORT_MAC_CTL 0x01 @@ -129,6 +132,7 @@ #define MV88E6XXX_PORT_SWITCH_ID_PROD_6350 0x3710 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6351 0x3750 #define MV88E6XXX_PORT_SWITCH_ID_PROD_6390 0x3900 +#define MV88E6XXX_PORT_SWITCH_ID_PROD_6393X 0x3930 #define MV88E6XXX_PORT_SWITCH_ID_REV_MASK 0x000f /* Offset 0x04: Port Control Register */ @@ -312,10 +316,13 @@ 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); +int mv88e6393x_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); phy_interface_t mv88e6390x_port_max_speed_mode(int port); +phy_interface_t mv88e6393x_port_max_speed_mode(int port); int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state); @@ -362,6 +369,8 @@ int mv88e6390_port_set_cmode(struct mv88e6xxx_chip *chip, int port, phy_interface_t mode); int mv88e6390x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, phy_interface_t mode); +int mv88e6393x_port_set_cmode(struct mv88e6xxx_chip *chip, int port, + phy_interface_t mode); int mv88e6185_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode); int mv88e6352_port_get_cmode(struct mv88e6xxx_chip *chip, int port, u8 *cmode); int mv88e6xxx_port_set_map_da(struct mv88e6xxx_chip *chip, int port); diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c index 9074d1097b614..e48057b366d51 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.c +++ b/drivers/net/dsa/mv88e6xxx/serdes.c @@ -526,6 +526,27 @@ int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane) return *lane == -1 ? -ENODEV : 0; } +int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane) +{ + u8 cmode = chip->ports[port].cmode; + + *lane = -1; + switch (port) { + case 0: + case 9: + case 10: + if (cmode == MV88E6XXX_PORT_STS_CMODE_1000BASEX || + cmode == MV88E6XXX_PORT_STS_CMODE_SGMII || + cmode == MV88E6XXX_PORT_STS_CMODE_2500BASEX || + cmode == MV88E6393_PORT_STS_CMODE_5GBASER || + cmode == MV88E6393_PORT_STS_CMODE_10GBASER || + cmode == MV88E6393_PORT_STS_CMODE_USXGMII) + *lane = port; + } + + return *lane == -1 ? -ENODEV : 0; +} + /* Set power up/down for 10GBASE-R and 10GBASE-X4/X2 */ static int mv88e6390_serdes_power_10g(struct mv88e6xxx_chip *chip, u8 lane, bool up) @@ -678,8 +699,8 @@ int mv88e6390_serdes_power(struct mv88e6xxx_chip *chip, int port, u8 lane, case MV88E6XXX_PORT_STS_CMODE_2500BASEX: err = mv88e6390_serdes_power_sgmii(chip, lane, up); break; - case MV88E6XXX_PORT_STS_CMODE_XAUI: - case MV88E6XXX_PORT_STS_CMODE_RXAUI: + case MV88E6XXX_PORT_STS_CMODE_XAUI: /* also MV88E6393_PORT_STS_CMODE_5GBASER */ + case MV88E6XXX_PORT_STS_CMODE_RXAUI: /* also MV88E6393_PORT_STS_CMODE_10GBASER */ err = mv88e6390_serdes_power_10g(chip, lane, up); break; } @@ -785,7 +806,10 @@ static int mv88e6390_serdes_pcs_get_state_10g(struct mv88e6xxx_chip *chip, state->link = !!(status & MDIO_STAT1_LSTATUS); if (state->link) { - state->speed = SPEED_10000; + if (state->interface == PHY_INTERFACE_MODE_5GBASER) + state->speed = SPEED_5000; + else + state->speed = SPEED_10000; state->duplex = DUPLEX_FULL; } @@ -801,8 +825,10 @@ int mv88e6390_serdes_pcs_get_state(struct mv88e6xxx_chip *chip, int port, case PHY_INTERFACE_MODE_2500BASEX: return mv88e6390_serdes_pcs_get_state_sgmii(chip, port, lane, state); + case PHY_INTERFACE_MODE_5GBASER: case PHY_INTERFACE_MODE_XAUI: case PHY_INTERFACE_MODE_RXAUI: + case PHY_INTERFACE_MODE_10GBASER: return mv88e6390_serdes_pcs_get_state_10g(chip, port, lane, state); @@ -878,6 +904,23 @@ static void mv88e6390_serdes_irq_link_sgmii(struct mv88e6xxx_chip *chip, dsa_port_phylink_mac_change(chip->ds, port, !!(bmsr & BMSR_LSTATUS)); } +static void mv88e6393x_serdes_irq_link_10g(struct mv88e6xxx_chip *chip, + int port, u8 lane) +{ + u16 status; + int err; + + /* If the link has dropped, we want to know about it. */ + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6390_10G_STAT1, &status); + if (err) { + dev_err(chip->dev, "can't read Serdes STAT1: %d\n", err); + return; + } + + dsa_port_phylink_mac_change(chip->ds, port, !!(status & MDIO_STAT1_LSTATUS)); +} + static int mv88e6390_serdes_irq_enable_sgmii(struct mv88e6xxx_chip *chip, u8 lane, bool enable) { @@ -906,6 +949,36 @@ int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, return 0; } +static int mv88e6393x_serdes_irq_enable_10g(struct mv88e6xxx_chip *chip, + u8 lane, bool enable) +{ + u16 val = 0; + + if (enable) + val |= MV88E6393X_10G_INT_LINK_CHANGE; + + return mv88e6390_serdes_write(chip, lane, MDIO_MMD_PHYXS, + MV88E6393X_10G_INT_ENABLE, val); +} + +int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, + bool enable) +{ + u8 cmode = chip->ports[port].cmode; + + switch (cmode) { + case MV88E6XXX_PORT_STS_CMODE_SGMII: + case MV88E6XXX_PORT_STS_CMODE_1000BASEX: + case MV88E6XXX_PORT_STS_CMODE_2500BASEX: + return mv88e6390_serdes_irq_enable_sgmii(chip, lane, enable); + case MV88E6393_PORT_STS_CMODE_5GBASER: + case MV88E6393_PORT_STS_CMODE_10GBASER: + return mv88e6393x_serdes_irq_enable_10g(chip, lane, enable); + } + + return 0; +} + static int mv88e6390_serdes_irq_status_sgmii(struct mv88e6xxx_chip *chip, u8 lane, u16 *status) { @@ -942,6 +1015,53 @@ irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, return ret; } +static int mv88e6393x_serdes_irq_status_10g(struct mv88e6xxx_chip *chip, + u8 lane, u16 *status) +{ + int err; + + err = mv88e6390_serdes_read(chip, lane, MDIO_MMD_PHYXS, + MV88E6393X_10G_INT_STATUS, status); + + return err; +} + +irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, + u8 lane) +{ + u8 cmode = chip->ports[port].cmode; + irqreturn_t ret = IRQ_NONE; + u16 status; + int err; + + switch (cmode) { + case MV88E6XXX_PORT_STS_CMODE_SGMII: + case MV88E6XXX_PORT_STS_CMODE_1000BASEX: + case MV88E6XXX_PORT_STS_CMODE_2500BASEX: + err = mv88e6390_serdes_irq_status_sgmii(chip, lane, &status); + if (err) + return ret; + if (status & (MV88E6390_SGMII_INT_LINK_DOWN | + MV88E6390_SGMII_INT_LINK_UP)) { + ret = IRQ_HANDLED; + mv88e6390_serdes_irq_link_sgmii(chip, port, lane); + } + break; + case MV88E6393_PORT_STS_CMODE_5GBASER: + case MV88E6393_PORT_STS_CMODE_10GBASER: + err = mv88e6393x_serdes_irq_status_10g(chip, lane, &status); + if (err) + return ret; + if (status & MV88E6393X_10G_INT_LINK_CHANGE) { + ret = IRQ_HANDLED; + mv88e6393x_serdes_irq_link_10g(chip, port, lane); + } + break; + } + + return ret; +} + unsigned int mv88e6390_serdes_irq_mapping(struct mv88e6xxx_chip *chip, int port) { return irq_find_mapping(chip->g2_irq.domain, port); diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h index 95d04dab8d251..3999195caa62a 100644 --- a/drivers/net/dsa/mv88e6xxx/serdes.h +++ b/drivers/net/dsa/mv88e6xxx/serdes.h @@ -42,6 +42,9 @@ /* 10GBASE-R and 10GBASE-X4/X2 */ #define MV88E6390_10G_CTRL1 (0x1000 + MDIO_CTRL1) #define MV88E6390_10G_STAT1 (0x1000 + MDIO_STAT1) +#define MV88E6393X_10G_INT_ENABLE 0x9000 +#define MV88E6393X_10G_INT_LINK_CHANGE BIT(2) +#define MV88E6393X_10G_INT_STATUS 0x9001 /* 1000BASE-X and SGMII */ #define MV88E6390_SGMII_BMCR (0x2000 + MII_BMCR) @@ -77,6 +80,7 @@ int mv88e6341_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); int mv88e6352_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); int mv88e6390_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); int mv88e6390x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); +int mv88e6393x_serdes_get_lane(struct mv88e6xxx_chip *chip, int port, u8 *lane); int mv88e6352_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port, u8 lane, unsigned int mode, phy_interface_t interface, @@ -109,10 +113,14 @@ int mv88e6352_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, bool enable); int mv88e6390_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, bool enable); +int mv88e6393x_serdes_irq_enable(struct mv88e6xxx_chip *chip, int port, u8 lane, + bool enable); irqreturn_t mv88e6352_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, u8 lane); irqreturn_t mv88e6390_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, u8 lane); +irqreturn_t mv88e6393x_serdes_irq_status(struct mv88e6xxx_chip *chip, int port, + u8 lane); int mv88e6352_serdes_get_sset_count(struct mv88e6xxx_chip *chip, int port); int mv88e6352_serdes_get_strings(struct mv88e6xxx_chip *chip, int port, uint8_t *data);