From patchwork Thu Jan 14 04:43:27 2021 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: 12018625 X-Patchwork-Delegate: kuba@kernel.org 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=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0341CC433E6 for ; Thu, 14 Jan 2021 04:44:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id CCB1623600 for ; Thu, 14 Jan 2021 04:44:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726742AbhANEob (ORCPT ); Wed, 13 Jan 2021 23:44:31 -0500 Received: from mail.kernel.org ([198.145.29.99]:34832 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726404AbhANEoX (ORCPT ); Wed, 13 Jan 2021 23:44:23 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id E7D2E238EC; Thu, 14 Jan 2021 04:43:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1610599423; bh=vg05N9MsH2t812UGcMDwUVmBTi1mTfXJOVduRfQ+sdQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OiRf0UDAr+ANAZU/gphYIYFBr0NjKzEOUODRgZyJ4YF1gjUbC8Ao+iqKxMfcVTw8I qWzf3H2oiQU/NRgrFzH3Hdd6+4A2qdry3UPNK2eeNEgmZdqdok2gcG1NbDO63j3JmO hh3tJ1TNGY5o+7z+nQVinu3d6JsMRHxAwxiuCWDKltYxaBvrMQwBkRHJoqOJ1e+h+w 2Jm+nUadMudvUiUzD5dwSwDfcx/3murunfWnHUJYZlRnqB6pZ9xys/6AXzCMTh8lvP wZSRtTF5iwBEkOVJQXcJIuP1KjxprNWuskWS+2ao6+Uzfb4BKRqsYnNAIcrwHJDto7 1qB7C5HmV4Vfg== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: netdev@vger.kernel.org Cc: Russell King , Andrew Lunn , Jakub Kicinski , davem@davemloft.net, pali@kernel.org, =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH net-next v5 1/5] net: sfp: add SFP_PASSWORD address Date: Thu, 14 Jan 2021 05:43:27 +0100 Message-Id: <20210114044331.5073-2-kabel@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210114044331.5073-1-kabel@kernel.org> References: <20210114044331.5073-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Add SFP_PASSWORD = 0x7b to the diagnostics enumerator. This address is described in SFF-8436 and SFF-8636. Signed-off-by: Marek Behún --- include/linux/sfp.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/sfp.h b/include/linux/sfp.h index 38893e4dd0f0..81b40b2d6b1b 100644 --- a/include/linux/sfp.h +++ b/include/linux/sfp.h @@ -490,6 +490,7 @@ enum { SFP_EXT_STATUS = 0x76, SFP_VSL = 0x78, + SFP_PASSWORD = 0x7b, SFP_PAGE = 0x7f, }; From patchwork Thu Jan 14 04:43:28 2021 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: 12018631 X-Patchwork-Delegate: kuba@kernel.org 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=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 213D0C433E9 for ; Thu, 14 Jan 2021 04:44:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E4C6D2376E for ; Thu, 14 Jan 2021 04:44:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726846AbhANEoc (ORCPT ); Wed, 13 Jan 2021 23:44:32 -0500 Received: from mail.kernel.org ([198.145.29.99]:34844 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726626AbhANEo1 (ORCPT ); Wed, 13 Jan 2021 23:44:27 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id BF2CC2396F; Thu, 14 Jan 2021 04:43:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1610599425; bh=4Q6293RSleJQKsmZHtR4ctGrpAE31mjPM4HJl8fjeLI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iBivhaGQuVLFyUUTYlVy35al5oXrQussEaMpgunWTiicsCbJtm567AssDP2O5nDTf 4cekkFUvOp27GspC+Mmksv8NljE31HR4THbpj6NfWtCdKWbnpnvO9zV9wqN0n60IgV /Zp4KEn4Y+bewX3WA1H3dFfUxSLu6Xt9M42pwOBHtPvZEShbIfAUabG4W/5AU8suE3 SN6AUeWLIbHSXySw7Jw490AV9p1wN/L5uXIbIKItmd+sP24vOPH1CifQuoU/DPVR44 YT9LO53oGnujmVjWKYcS2ouI9WLC7u873fH14uig5FyI0uxWuUphCjdkQXzTrAPDki DZmhtlnJFQnZA== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: netdev@vger.kernel.org Cc: Russell King , Andrew Lunn , Jakub Kicinski , davem@davemloft.net, pali@kernel.org, =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH net-next v5 2/5] net: phy: mdio-i2c: support I2C MDIO protocol for RollBall SFP modules Date: Thu, 14 Jan 2021 05:43:28 +0100 Message-Id: <20210114044331.5073-3-kabel@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210114044331.5073-1-kabel@kernel.org> References: <20210114044331.5073-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Some multigig SFPs from RollBall and Hilink do not expose functional MDIO access to the internal PHY of the SFP via I2C address 0x56 (although there seems to be read-only clause 22 access on this address). Instead these SFPs PHY can be accessed via I2C via the SFP Enhanced Digital Diagnostic Interface - I2C address 0x51. The SFP_PAGE has to be selected to 3 and the password must be filled with 0xff bytes for this PHY communication to work. This extends the mdio-i2c driver to support this protocol by adding a special parameter to mdio_i2c_alloc function via which this RollBall protocol can be selected. Signed-off-by: Marek Behún Cc: Andrew Lunn Cc: Russell King --- drivers/net/mdio/mdio-i2c.c | 308 +++++++++++++++++++++++++++++++++- drivers/net/phy/sfp.c | 2 +- include/linux/mdio/mdio-i2c.h | 8 +- 3 files changed, 311 insertions(+), 7 deletions(-) diff --git a/drivers/net/mdio/mdio-i2c.c b/drivers/net/mdio/mdio-i2c.c index 09200a70b315..991a449b3163 100644 --- a/drivers/net/mdio/mdio-i2c.c +++ b/drivers/net/mdio/mdio-i2c.c @@ -3,6 +3,7 @@ * MDIO I2C bridge * * Copyright (C) 2015-2016 Russell King + * Copyright (C) 2021 Marek Behun * * Network PHYs can appear on I2C buses when they are part of SFP module. * This driver exposes these PHYs to the networking PHY code, allowing @@ -12,6 +13,7 @@ #include #include #include +#include /* * I2C bus addresses 0x50 and 0x51 are normally an EEPROM, which is @@ -28,7 +30,7 @@ static unsigned int i2c_mii_phy_addr(int phy_id) return phy_id + 0x40; } -static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg) +static int i2c_mii_read_default(struct mii_bus *bus, int phy_id, int reg) { struct i2c_adapter *i2c = bus->priv; struct i2c_msg msgs[2]; @@ -62,7 +64,8 @@ static int i2c_mii_read(struct mii_bus *bus, int phy_id, int reg) return data[0] << 8 | data[1]; } -static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) +static int i2c_mii_write_default(struct mii_bus *bus, int phy_id, int reg, + u16 val) { struct i2c_adapter *i2c = bus->priv; struct i2c_msg msg; @@ -91,9 +94,286 @@ static int i2c_mii_write(struct mii_bus *bus, int phy_id, int reg, u16 val) return ret < 0 ? ret : 0; } -struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c) +/* RollBall SFPs do not access internal PHY via I2C address 0x56, but + * instead via address 0x51, when SFP page is set to 0x03 and password to + * 0xffffffff. + * + * address size contents description + * ------- ---- -------- ----------- + * 0x80 1 CMD 0x01/0x02/0x04 for write/read/done + * 0x81 1 DEV Clause 45 device + * 0x82 2 REG Clause 45 register + * 0x84 2 VAL Register value + */ +#define ROLLBALL_PHY_I2C_ADDR 0x51 + +#define ROLLBALL_CMD_ADDR 0x80 +#define ROLLBALL_DATA_ADDR 0x81 + +#define ROLLBALL_CMD_WRITE 0x01 +#define ROLLBALL_CMD_READ 0x02 +#define ROLLBALL_CMD_DONE 0x04 + +#define SFP_PAGE_ROLLBALL_MDIO 3 + +static int __i2c_transfer_err(struct i2c_adapter *i2c, struct i2c_msg *msgs, + int num) +{ + int ret; + + ret = __i2c_transfer(i2c, msgs, num); + if (ret < 0) + return ret; + else if (ret != num) + return -EIO; + else + return 0; +} + +static int __i2c_rollball_get_page(struct i2c_adapter *i2c, int bus_addr, + u8 *page) +{ + struct i2c_msg msgs[2]; + u8 addr = SFP_PAGE; + + msgs[0].addr = bus_addr; + msgs[0].flags = 0; + msgs[0].len = 1; + msgs[0].buf = &addr; + + msgs[1].addr = bus_addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = 1; + msgs[1].buf = page; + + return __i2c_transfer_err(i2c, msgs, 2); +} + +static int __i2c_rollball_set_page(struct i2c_adapter *i2c, int bus_addr, + u8 page) +{ + struct i2c_msg msg; + u8 buf[2]; + + buf[0] = SFP_PAGE; + buf[1] = page; + + msg.addr = bus_addr; + msg.flags = 0; + msg.len = 2; + msg.buf = buf; + + return __i2c_transfer_err(i2c, &msg, 1); +} + +/* In order to not interfere with other SFP code (which possibly may manipulate + * SFP_PAGE), for every transfer we do this: + * 1. lock the bus + * 2. save content of SFP_PAGE + * 3. set SFP_PAGE to 3 + * 4. do the transfer + * 5. restore original SFP_PAGE + * 6. unlock the bus + * Note that one might think that steps 2 to 5 could be theoretically done all + * in one call to i2c_transfer (by constructing msgs array in such a way), but + * unfortunately tests show that this does not work :-( Changed SFP_PAGE does + * not take into account until i2c_transfer() is done. + */ +static int i2c_transfer_rollball(struct i2c_adapter *i2c, + struct i2c_msg *msgs, int num) +{ + int ret, main_err = 0; + u8 saved_page; + + i2c_lock_bus(i2c, I2C_LOCK_SEGMENT); + + /* save original page */ + ret = __i2c_rollball_get_page(i2c, msgs->addr, &saved_page); + if (ret) + goto unlock; + + /* change to RollBall MDIO page */ + ret = __i2c_rollball_set_page(i2c, msgs->addr, SFP_PAGE_ROLLBALL_MDIO); + if (ret) + goto unlock; + + /* do the transfer; we try to restore original page if this fails */ + ret = __i2c_transfer_err(i2c, msgs, num); + if (ret) + main_err = ret; + + /* restore original page */ + ret = __i2c_rollball_set_page(i2c, msgs->addr, saved_page); + +unlock: + i2c_unlock_bus(i2c, I2C_LOCK_SEGMENT); + + return main_err ? : ret; +} + +static int i2c_rollball_mii_poll(struct mii_bus *bus, int bus_addr, u8 *buf, + size_t len) +{ + struct i2c_adapter *i2c = bus->priv; + struct i2c_msg msgs[2]; + u8 cmd_addr, tmp, *res; + int i, ret; + + cmd_addr = ROLLBALL_CMD_ADDR; + + res = buf ? buf : &tmp; + len = buf ? len : 1; + + msgs[0].addr = bus_addr; + msgs[0].flags = 0; + msgs[0].len = 1; + msgs[0].buf = &cmd_addr; + + msgs[1].addr = bus_addr; + msgs[1].flags = I2C_M_RD; + msgs[1].len = len; + msgs[1].buf = res; + + /* By experiment it takes up to 70 ms to access a register for these + * SFPs. Sleep 20ms between iterations and try 10 times. + */ + i = 10; + do { + msleep(20); + + ret = i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); + if (ret) + return ret; + + if (*res == ROLLBALL_CMD_DONE) + return 0; + } while (i-- > 0); + + dev_dbg(&bus->dev, "poll timed out\n"); + + return -ETIMEDOUT; +} + +static int i2c_rollball_mii_cmd(struct mii_bus *bus, int bus_addr, u8 cmd, + u8 *data, size_t len) +{ + struct i2c_adapter *i2c = bus->priv; + struct i2c_msg msgs[2]; + u8 cmdbuf[2]; + + cmdbuf[0] = ROLLBALL_CMD_ADDR; + cmdbuf[1] = cmd; + + msgs[0].addr = bus_addr; + msgs[0].flags = 0; + msgs[0].len = len; + msgs[0].buf = data; + + msgs[1].addr = bus_addr; + msgs[1].flags = 0; + msgs[1].len = sizeof(cmdbuf); + msgs[1].buf = cmdbuf; + + return i2c_transfer_rollball(i2c, msgs, ARRAY_SIZE(msgs)); +} + +static int i2c_mii_read_rollball(struct mii_bus *bus, int phy_id, int reg) +{ + u8 buf[4], res[6]; + int bus_addr, ret; + u16 val; + + if (!(reg & MII_ADDR_C45)) + return -EOPNOTSUPP; + + bus_addr = i2c_mii_phy_addr(phy_id); + if (bus_addr != ROLLBALL_PHY_I2C_ADDR) + return 0xffff; + + buf[0] = ROLLBALL_DATA_ADDR; + buf[1] = (reg >> 16) & 0x1f; + buf[2] = (reg >> 8) & 0xff; + buf[3] = reg & 0xff; + + ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_READ, buf, + sizeof(buf)); + if (ret < 0) + return ret; + + ret = i2c_rollball_mii_poll(bus, bus_addr, res, sizeof(res)); + if (ret == -ETIMEDOUT) + return 0xffff; + else if (ret < 0) + return ret; + + val = res[4] << 8 | res[5]; + + return val; +} + +static int i2c_mii_write_rollball(struct mii_bus *bus, int phy_id, int reg, + u16 val) +{ + int bus_addr, ret; + u8 buf[6]; + + if (!(reg & MII_ADDR_C45)) + return -EOPNOTSUPP; + + bus_addr = i2c_mii_phy_addr(phy_id); + if (bus_addr != ROLLBALL_PHY_I2C_ADDR) + return 0; + + buf[0] = ROLLBALL_DATA_ADDR; + buf[1] = (reg >> 16) & 0x1f; + buf[2] = (reg >> 8) & 0xff; + buf[3] = reg & 0xff; + buf[4] = val >> 8; + buf[5] = val & 0xff; + + ret = i2c_rollball_mii_cmd(bus, bus_addr, ROLLBALL_CMD_WRITE, buf, + sizeof(buf)); + if (ret < 0) + return ret; + + ret = i2c_rollball_mii_poll(bus, bus_addr, NULL, 0); + if (ret < 0) + return ret; + + return 0; +} + +static int i2c_mii_init_rollball(struct i2c_adapter *i2c) +{ + struct i2c_msg msg; + u8 pw[5]; + int ret; + + pw[0] = SFP_PASSWORD; + pw[1] = 0xff; + pw[2] = 0xff; + pw[3] = 0xff; + pw[4] = 0xff; + + msg.addr = ROLLBALL_PHY_I2C_ADDR; + msg.flags = 0; + msg.len = sizeof(pw); + msg.buf = pw; + + ret = i2c_transfer(i2c, &msg, 1); + if (ret < 0) + return ret; + else if (ret != 1) + return -EIO; + else + return 0; +} + +struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, + enum mdio_i2c_proto protocol) { struct mii_bus *mii; + int ret; if (!i2c_check_functionality(i2c, I2C_FUNC_I2C)) return ERR_PTR(-EINVAL); @@ -104,10 +384,28 @@ struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c) snprintf(mii->id, MII_BUS_ID_SIZE, "i2c:%s", dev_name(parent)); mii->parent = parent; - mii->read = i2c_mii_read; - mii->write = i2c_mii_write; mii->priv = i2c; + switch (protocol) { + case MDIO_I2C_ROLLBALL: + ret = i2c_mii_init_rollball(i2c); + if (ret < 0) { + dev_err(parent, + "Cannot initialize RollBall MDIO I2C protocol: %d\n", + ret); + mdiobus_free(mii); + return ERR_PTR(ret); + } + + mii->read = i2c_mii_read_rollball; + mii->write = i2c_mii_write_rollball; + break; + default: + mii->read = i2c_mii_read_default; + mii->write = i2c_mii_write_default; + break; + } + return mii; } EXPORT_SYMBOL_GPL(mdio_i2c_alloc); diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index b2a5ed6915fa..fac5407c4b87 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -423,7 +423,7 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) sfp->read = sfp_i2c_read; sfp->write = sfp_i2c_write; - i2c_mii = mdio_i2c_alloc(sfp->dev, i2c); + i2c_mii = mdio_i2c_alloc(sfp->dev, i2c, MDIO_I2C_DEFAULT); if (IS_ERR(i2c_mii)) return PTR_ERR(i2c_mii); diff --git a/include/linux/mdio/mdio-i2c.h b/include/linux/mdio/mdio-i2c.h index b1d27f7cd23f..53eedb0dc1d3 100644 --- a/include/linux/mdio/mdio-i2c.h +++ b/include/linux/mdio/mdio-i2c.h @@ -11,6 +11,12 @@ struct device; struct i2c_adapter; struct mii_bus; -struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c); +enum mdio_i2c_proto { + MDIO_I2C_DEFAULT, + MDIO_I2C_ROLLBALL, +}; + +struct mii_bus *mdio_i2c_alloc(struct device *parent, struct i2c_adapter *i2c, + enum mdio_i2c_proto protocol); #endif From patchwork Thu Jan 14 04:43:29 2021 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: 12018633 X-Patchwork-Delegate: kuba@kernel.org 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=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4500FC43381 for ; Thu, 14 Jan 2021 04:44:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 0C36C23447 for ; Thu, 14 Jan 2021 04:44:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727011AbhANEof (ORCPT ); Wed, 13 Jan 2021 23:44:35 -0500 Received: from mail.kernel.org ([198.145.29.99]:34860 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726640AbhANEo1 (ORCPT ); Wed, 13 Jan 2021 23:44:27 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 7F1FF2395B; Thu, 14 Jan 2021 04:43:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1610599426; bh=JkPVPwYLS4y43fsbynG1MyOKpEOsyx6ePisAgjEQMhc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uVRRk3t6dSdqg7qbuj44yE6CxbKrWEAEqcVbZTM8GIGs3F+5hbl7Z74Kch5QOM8LA iji7a52ESWX5b0WopDy9zbpIG9MxaHkOX+UTIexSz+9SxT10ctd2iGnQCVVzc5cu9k Oh9eI224R2R2TCU3kEGby9n9EN6HUfLFjIaVDhTuLPuJi6CeeSDbl3YekeDbdd/T1x cO4Lj90Y0vohBMdRGC1Hj86eReQyjbIbmEUUbax5AU1JRxQyo3kqPbrO0La1AeqWsK 6zTthUG2Sa16m5zXniGOt1Q9pvfqJaNgAW/nD18QNw6r11Io7vkPfdrac6U+sel8MS Kshx4eh9RFqFQ== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: netdev@vger.kernel.org Cc: Russell King , Andrew Lunn , Jakub Kicinski , davem@davemloft.net, pali@kernel.org, =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH net-next v5 3/5] net: phylink: allow attaching phy for SFP modules on 802.3z mode Date: Thu, 14 Jan 2021 05:43:29 +0100 Message-Id: <20210114044331.5073-4-kabel@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210114044331.5073-1-kabel@kernel.org> References: <20210114044331.5073-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Some SFPs may contain an internal PHY which may in some cases want to connect with the host interface in 1000base-x/2500base-x mode. Do not fail if such PHY is being attached in one of these PHY interface modes. Signed-off-by: Marek Behún Reviewed-by: Russell King Reviewed-by: Pali Rohár Cc: Andrew Lunn --- drivers/net/phy/phylink.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c index 84f6e197f965..f97d041f82f4 100644 --- a/drivers/net/phy/phylink.c +++ b/drivers/net/phy/phylink.c @@ -1018,7 +1018,7 @@ static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy, { if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED || (pl->cfg_link_an_mode == MLO_AN_INBAND && - phy_interface_mode_is_8023z(interface)))) + phy_interface_mode_is_8023z(interface) && !pl->sfp_bus))) return -EINVAL; if (pl->phydev) @@ -2069,9 +2069,6 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode, phylink_an_mode_str(mode), phy_modes(config.interface), __ETHTOOL_LINK_MODE_MASK_NBITS, support); - if (phy_interface_mode_is_8023z(iface) && pl->phydev) - return -EINVAL; - changed = !linkmode_equal(pl->supported, support); if (changed) { linkmode_copy(pl->supported, support); From patchwork Thu Jan 14 04:43:30 2021 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: 12018629 X-Patchwork-Delegate: kuba@kernel.org 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=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5CAE4C433E0 for ; Thu, 14 Jan 2021 04:44:39 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2F72F23600 for ; Thu, 14 Jan 2021 04:44:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726904AbhANEof (ORCPT ); Wed, 13 Jan 2021 23:44:35 -0500 Received: from mail.kernel.org ([198.145.29.99]:34872 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726644AbhANEo3 (ORCPT ); Wed, 13 Jan 2021 23:44:29 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id 4070F23976; Thu, 14 Jan 2021 04:43:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1610599428; bh=tosZN6YHVNto1dqqDrDqAohbGtB+J/j1DfbuxP4Ybq8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=dt6DTAyiIBq2F8wv7AE+lI9qSHA6soNytPHLidd7CaFOMdcPAgpKAFvQzamEuKwD+ icTVIp8hWThJDljtJ9I4g0ySIrUVe1V2BgXrXoYQgK/VV01fNU69qQveo076LHYrHY fRgnpfReDng8IioH5A4kU5xZXudlgeL3kvkH1aY+dyi35ObjE3lD6gaIKgB9cfm6oj LWZlGNREP5XR0z/RBSB9RifupStoAAeol22W69PogScXIzZIOL0l8BmWZ061iZOol4 DhGCHnm10ozS2/yTHX+P24hbNJvB4znBpvZ9pAVhXWiw/HyIlOKNaIZWdQ2UVGsh9v oiYVV8jugkpBw== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: netdev@vger.kernel.org Cc: Russell King , Andrew Lunn , Jakub Kicinski , davem@davemloft.net, pali@kernel.org, =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH net-next v5 4/5] net: sfp: create/destroy I2C mdiobus before PHY probe/after PHY release Date: Thu, 14 Jan 2021 05:43:30 +0100 Message-Id: <20210114044331.5073-5-kabel@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210114044331.5073-1-kabel@kernel.org> References: <20210114044331.5073-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org Instead of configuring the I2C mdiobus when SFP driver is probed, create/destroy the mdiobus before the PHY is probed for/after it is released. This way we can tell the mdio-i2c code which protocol to use for each SFP transceiver. Signed-off-by: Marek Behún Reviewed-by: Pali Rohár Cc: Andrew Lunn Cc: Russell King --- drivers/net/phy/sfp.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index fac5407c4b87..d1b655f805ab 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -218,6 +218,7 @@ struct sfp { struct i2c_adapter *i2c; struct mii_bus *i2c_mii; struct sfp_bus *sfp_bus; + enum mdio_i2c_proto mdio_protocol; struct phy_device *mod_phy; const struct sff_data *type; size_t i2c_block_size; @@ -413,9 +414,6 @@ static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf, static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) { - struct mii_bus *i2c_mii; - int ret; - if (!i2c_check_functionality(i2c, I2C_FUNC_I2C)) return -EINVAL; @@ -423,7 +421,15 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) sfp->read = sfp_i2c_read; sfp->write = sfp_i2c_write; - i2c_mii = mdio_i2c_alloc(sfp->dev, i2c, MDIO_I2C_DEFAULT); + return 0; +} + +static int sfp_i2c_mdiobus_create(struct sfp *sfp) +{ + struct mii_bus *i2c_mii; + int ret; + + i2c_mii = mdio_i2c_alloc(sfp->dev, sfp->i2c, sfp->mdio_protocol); if (IS_ERR(i2c_mii)) return PTR_ERR(i2c_mii); @@ -441,6 +447,12 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c) return 0; } +static void sfp_i2c_mdiobus_destroy(struct sfp *sfp) +{ + mdiobus_unregister(sfp->i2c_mii); + sfp->i2c_mii = NULL; +} + /* Interface */ static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len) { @@ -1881,6 +1893,8 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) else sfp->module_t_start_up = T_START_UP; + sfp->mdio_protocol = MDIO_I2C_DEFAULT; + return 0; } @@ -2051,6 +2065,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) sfp_module_stop(sfp->sfp_bus); if (sfp->mod_phy) sfp_sm_phy_detach(sfp); + if (sfp->i2c_mii) + sfp_i2c_mdiobus_destroy(sfp); sfp_module_tx_disable(sfp); sfp_soft_stop_poll(sfp); sfp_sm_next(sfp, SFP_S_DOWN, 0); @@ -2113,6 +2129,12 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) sfp->sm_fault_retries == N_FAULT_INIT); } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) { init_done: + /* Create mdiobus and start trying for PHY */ + ret = sfp_i2c_mdiobus_create(sfp); + if (ret < 0) { + sfp_sm_next(sfp, SFP_S_FAIL, 0); + break; + } sfp->sm_phy_retries = R_PHY_RETRY; goto phy_probe; } From patchwork Thu Jan 14 04:43:31 2021 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: 12018635 X-Patchwork-Delegate: kuba@kernel.org 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=-19.2 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8EC5C433DB for ; Thu, 14 Jan 2021 04:45:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 8D22023447 for ; Thu, 14 Jan 2021 04:45:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727068AbhANEpD (ORCPT ); Wed, 13 Jan 2021 23:45:03 -0500 Received: from mail.kernel.org ([198.145.29.99]:34988 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726640AbhANEpC (ORCPT ); Wed, 13 Jan 2021 23:45:02 -0500 Received: by mail.kernel.org (Postfix) with ESMTPSA id E8C20239D3; Thu, 14 Jan 2021 04:43:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1610599430; bh=G9xPNinZ7l0pEHVaxcUfxEJr7h8qSlkgWk0+EGwZbaw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fXDALwgBCQnKhwQlYKgrcxWMUYzVqp4VDJz4iQpYLht2x6Eh8AbggUhx7oOEzSBqU tdz+Vd0CWuKDRrf9neQEBkl18YzG267rGuQgjZcBOOGZEF6xS+SlEVEY/9o5/RuG6U MtzOdrnA02zBC7SQgeFltj4QH9ycs3sodCPdJ/iYqsb5umkg2DYlIiYpmXIQWJyEFd BwW6bC9HnvuZEm8Z70/7Wcot4OsRkEwaWJjk8ZEt5zEnCooTNaVucYmvoTF2fFMI91 oYuLupnSPSAgkcrcbtwJ+WeI1/Iv0zAowhdfMCJ4nw598LGkuojPu01b3mREGWKQMP ZksARDQoHtCCQ== From: =?utf-8?q?Marek_Beh=C3=BAn?= To: netdev@vger.kernel.org Cc: Russell King , Andrew Lunn , Jakub Kicinski , davem@davemloft.net, pali@kernel.org, =?utf-8?q?Marek_Beh=C3=BAn?= Subject: [PATCH net-next v5 5/5] net: sfp: add support for multigig RollBall transceivers Date: Thu, 14 Jan 2021 05:43:31 +0100 Message-Id: <20210114044331.5073-6-kabel@kernel.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20210114044331.5073-1-kabel@kernel.org> References: <20210114044331.5073-1-kabel@kernel.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org X-Patchwork-Delegate: kuba@kernel.org This adds support for multigig copper SFP modules from RollBall/Hilink. These modules have a specific way to access clause 45 registers of the internal PHY. We also need to wait at least 22 seconds after deasserting TX disable before accessing the PHY. The code waits for 25 seconds just to be sure. Signed-off-by: Marek Behún Reviewed-by: Russell King Cc: Andrew Lunn --- drivers/net/phy/sfp.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c index d1b655f805ab..9f4270c19380 100644 --- a/drivers/net/phy/sfp.c +++ b/drivers/net/phy/sfp.c @@ -166,6 +166,7 @@ static const enum gpiod_flags gpio_flags[] = { * on board (for a copper SFP) time to initialise. */ #define T_WAIT msecs_to_jiffies(50) +#define T_WAIT_ROLLBALL msecs_to_jiffies(25000) #define T_START_UP msecs_to_jiffies(300) #define T_START_UP_BAD_GPON msecs_to_jiffies(60000) @@ -205,8 +206,11 @@ static const enum gpiod_flags gpio_flags[] = { /* SFP modules appear to always have their PHY configured for bus address * 0x56 (which with mdio-i2c, translates to a PHY address of 22). + * RollBall SFPs access phy via SFP Enhanced Digital Diagnostic Interface + * via address 0x51 (mdio-i2c will use RollBall protocol on this address). */ -#define SFP_PHY_ADDR 22 +#define SFP_PHY_ADDR 22 +#define SFP_PHY_ADDR_ROLLBALL 17 struct sff_data { unsigned int gpios; @@ -219,6 +223,7 @@ struct sfp { struct mii_bus *i2c_mii; struct sfp_bus *sfp_bus; enum mdio_i2c_proto mdio_protocol; + int phy_addr; struct phy_device *mod_phy; const struct sff_data *type; size_t i2c_block_size; @@ -251,6 +256,7 @@ struct sfp { struct sfp_eeprom_id id; unsigned int module_power_mW; unsigned int module_t_start_up; + unsigned int module_t_wait; #if IS_ENABLED(CONFIG_HWMON) struct sfp_diag diag; @@ -1505,7 +1511,7 @@ static int sfp_sm_probe_phy(struct sfp *sfp, bool is_c45) struct phy_device *phy; int err; - phy = get_phy_device(sfp->i2c_mii, SFP_PHY_ADDR, is_c45); + phy = get_phy_device(sfp->i2c_mii, sfp->phy_addr, is_c45); if (phy == ERR_PTR(-ENODEV)) return PTR_ERR(phy); if (IS_ERR(phy)) { @@ -1895,6 +1901,23 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report) sfp->mdio_protocol = MDIO_I2C_DEFAULT; + sfp->phy_addr = SFP_PHY_ADDR; + sfp->module_t_wait = T_WAIT; + + if (((!memcmp(id.base.vendor_name, "OEM ", 16) || + !memcmp(id.base.vendor_name, "Turris ", 16)) && + (!memcmp(id.base.vendor_pn, "SFP-10G-T ", 16) || + !memcmp(id.base.vendor_pn, "RTSFP-10", 8)))) { + sfp->mdio_protocol = MDIO_I2C_ROLLBALL; + sfp->phy_addr = SFP_PHY_ADDR_ROLLBALL; + sfp->module_t_wait = T_WAIT_ROLLBALL; + + /* RollBall SFPs may have wrong (zero) extended compliance code + * burned in EEPROM. For PHY probing we need the correct one. + */ + id.base.extended_cc = SFF8024_ECC_10GBASE_T_SFI; + } + return 0; } @@ -2090,9 +2113,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) /* We need to check the TX_FAULT state, which is not defined * while TX_DISABLE is asserted. The earliest we want to do - * anything (such as probe for a PHY) is 50ms. + * anything (such as probe for a PHY) is 50ms. (or more on + * specific modules). */ - sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT); + sfp_sm_next(sfp, SFP_S_WAIT, sfp->module_t_wait); break; case SFP_S_WAIT: @@ -2106,8 +2130,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event) * deasserting. */ timeout = sfp->module_t_start_up; - if (timeout > T_WAIT) - timeout -= T_WAIT; + if (timeout > sfp->module_t_wait) + timeout -= sfp->module_t_wait; else timeout = 1;