From patchwork Mon Nov 20 08:34:15 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Leitner X-Patchwork-Id: 839471 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ygMX86J0Gz9ryv for ; Mon, 20 Nov 2017 19:36:56 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751274AbdKTIgn (ORCPT ); Mon, 20 Nov 2017 03:36:43 -0500 Received: from relay04.alfahosting-server.de ([109.237.142.240]:2742 "EHLO relay04.alfahosting-server.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750974AbdKTIff (ORCPT ); Mon, 20 Nov 2017 03:35:35 -0500 Received: by relay01.alfahosting-server.de (Postfix, from userid 1001) id A4EA932C2312; Mon, 20 Nov 2017 09:35:33 +0100 (CET) X-Spam-DCC: : X-Spam-Level: X-Spam-Status: No, score=-999.0 required=7.0 tests=BAYES_60, D_SENT_WITH_SASL autolearn=disabled version=3.2.5 Received: from alfa3028.alfahosting-server.de (alfa3028.alfahosting-server.de [109.237.138.38]) by relay01.alfahosting-server.de (Postfix) with ESMTPS id E17E932C31F5; Mon, 20 Nov 2017 09:35:31 +0100 (CET) Received: from localhost.localdomain (unknown [91.230.2.244]) (Authenticated sender: yes) by alfa3028.alfahosting-server.de (Postfix) with ESMTPA id A7DEC430D437; Mon, 20 Nov 2017 09:35:31 +0100 (CET) From: Richard Leitner To: f.fainelli@gmail.com, fugang.duan@nxp.com, andrew@lunn.ch Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, richard.leitner@skidata.com Subject: [PATCH v2 1/3] net: ethernet: freescale: simplify fec_reset_phy Date: Mon, 20 Nov 2017 09:34:15 +0100 Message-Id: <20171120083417.32558-2-dev@g0hl1n.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171120083417.32558-1-dev@g0hl1n.net> References: <20171120083417.32558-1-dev@g0hl1n.net> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Richard Leitner The fec_reset_phy function allowed only one execution during probeing. To make it more usable move the dt parsing and gpio allocation to the probe function. The parameters of the phy reset are added to the fec_enet_private struct. As a result the fec_reset_phy function may be called anytime after probe. One checkpatch.pl warning (too long line) is ignored. This is due to the fact a string (dt property name) otherwise needs to be split over multiple lines, which is counterproductive for the readability. Signed-off-by: Richard Leitner --- drivers/net/ethernet/freescale/fec.h | 4 ++ drivers/net/ethernet/freescale/fec_main.c | 88 ++++++++++++++++--------------- 2 files changed, 50 insertions(+), 42 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h index 5385074b3b7d..401c4eabf08a 100644 --- a/drivers/net/ethernet/freescale/fec.h +++ b/drivers/net/ethernet/freescale/fec.h @@ -539,6 +539,10 @@ struct fec_enet_private { int pause_flag; int wol_flag; u32 quirks; + int phy_reset; + int phy_reset_duration; + int phy_reset_post_delay; + bool phy_reset_active_high; struct napi_struct napi; int csum_flags; diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 610573855213..06a7caca0cee 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3212,62 +3212,36 @@ static int fec_enet_init(struct net_device *ndev) } #ifdef CONFIG_OF -static int fec_reset_phy(struct platform_device *pdev) +static int fec_reset_phy(struct net_device *ndev) { - int err, phy_reset; - bool active_high = false; - int msec = 1, phy_post_delay = 0; - struct device_node *np = pdev->dev.of_node; - - if (!np) - return 0; - - err = of_property_read_u32(np, "phy-reset-duration", &msec); - /* A sane reset duration should not be longer than 1s */ - if (!err && msec > 1000) - msec = 1; + struct fec_enet_private *fep = netdev_priv(ndev); - phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); - if (phy_reset == -EPROBE_DEFER) - return phy_reset; - else if (!gpio_is_valid(phy_reset)) + if (!fep->phy_reset) return 0; - err = of_property_read_u32(np, "phy-reset-post-delay", &phy_post_delay); - /* valid reset duration should be less than 1s */ - if (!err && phy_post_delay > 1000) - return -EINVAL; - - active_high = of_property_read_bool(np, "phy-reset-active-high"); + gpio_set_value_cansleep(fep->phy_reset, fep->phy_reset_active_high); - err = devm_gpio_request_one(&pdev->dev, phy_reset, - active_high ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW, - "phy-reset"); - if (err) { - dev_err(&pdev->dev, "failed to get phy-reset-gpios: %d\n", err); - return err; - } - - if (msec > 20) - msleep(msec); + if (fep->phy_reset_duration > 20) + msleep(fep->phy_reset_duration); else - usleep_range(msec * 1000, msec * 1000 + 1000); + usleep_range(fep->phy_reset_duration * 1000, + fep->phy_reset_duration * 1000 + 1000); - gpio_set_value_cansleep(phy_reset, !active_high); + gpio_set_value_cansleep(fep->phy_reset, !fep->phy_reset_active_high); - if (!phy_post_delay) + if (!fep->phy_reset_post_delay) return 0; - if (phy_post_delay > 20) - msleep(phy_post_delay); + if (fep->phy_reset_post_delay > 20) + msleep(fep->phy_reset_post_delay); else - usleep_range(phy_post_delay * 1000, - phy_post_delay * 1000 + 1000); + usleep_range(fep->phy_reset_post_delay * 1000, + fep->phy_reset_post_delay * 1000 + 1000); return 0; } #else /* CONFIG_OF */ -static int fec_reset_phy(struct platform_device *pdev) +static int fec_reset_phy(struct net_device *ndev) { /* * In case of platform probe, the reset has been done @@ -3400,6 +3374,36 @@ fec_probe(struct platform_device *pdev) } fep->phy_node = phy_node; + fep->phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); + if (gpio_is_valid(fep->phy_reset)) { + ret = of_property_read_u32(np, "phy-reset-duration", + &fep->phy_reset_duration); + /* A sane reset duration should not be longer than 1s */ + if (!ret && fep->phy_reset_post_delay > 1000) + fep->phy_reset_post_delay = 1; + + ret = of_property_read_u32(np, "phy-reset-post-delay", + &fep->phy_reset_post_delay); + /* valid post reset delay should be less than 1s */ + if (!ret && fep->phy_reset_post_delay > 1000) + fep->phy_reset_post_delay = 1; + + fep->phy_reset_active_high = of_property_read_bool(np, "phy-reset-active-high"); + + ret = devm_gpio_request_one(&pdev->dev, fep->phy_reset, + fep->phy_reset_active_high ? + GPIOF_OUT_INIT_HIGH : + GPIOF_OUT_INIT_LOW, + "phy-reset"); + if (ret) { + dev_err(&pdev->dev, "failed to get reset-gpios: %d\n", + ret); + goto failed_phy; + } + } else { + fep->phy_reset = 0; + } + ret = of_get_phy_mode(pdev->dev.of_node); if (ret < 0) { pdata = dev_get_platdata(&pdev->dev); @@ -3472,7 +3476,7 @@ fec_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - ret = fec_reset_phy(pdev); + ret = fec_reset_phy(ndev); if (ret) goto failed_reset; From patchwork Mon Nov 20 08:34:16 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Leitner X-Patchwork-Id: 839469 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ygMWS2hy5z9ryv for ; Mon, 20 Nov 2017 19:36:20 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751155AbdKTIfg (ORCPT ); Mon, 20 Nov 2017 03:35:36 -0500 Received: from relay15.alfahosting-server.de ([109.237.142.229]:46953 "EHLO relay15.alfahosting-server.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751061AbdKTIff (ORCPT ); Mon, 20 Nov 2017 03:35:35 -0500 Received: by relay01.alfahosting-server.de (Postfix, from userid 1001) id 6EDC732C308F; Mon, 20 Nov 2017 09:35:33 +0100 (CET) X-Spam-DCC: : X-Spam-Level: X-Spam-Status: No, score=-1000.0 required=7.0 tests=BAYES_50, D_SENT_WITH_SASL autolearn=disabled version=3.2.5 Received: from alfa3028.alfahosting-server.de (alfa3028.alfahosting-server.de [109.237.138.38]) by relay01.alfahosting-server.de (Postfix) with ESMTPS id 30B5D32C31FC; Mon, 20 Nov 2017 09:35:32 +0100 (CET) Received: from localhost.localdomain (unknown [91.230.2.244]) (Authenticated sender: yes) by alfa3028.alfahosting-server.de (Postfix) with ESMTPA id E33C1430D55D; Mon, 20 Nov 2017 09:35:31 +0100 (CET) From: Richard Leitner To: f.fainelli@gmail.com, fugang.duan@nxp.com, andrew@lunn.ch Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, richard.leitner@skidata.com Subject: [PATCH v2 2/3] include: linux: phy: harmonize phy_id{,_mask} type Date: Mon, 20 Nov 2017 09:34:16 +0100 Message-Id: <20171120083417.32558-3-dev@g0hl1n.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171120083417.32558-1-dev@g0hl1n.net> References: <20171120083417.32558-1-dev@g0hl1n.net> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Richard Leitner Previously phy_id was u32 and phy_id_mask was unsigned int. As the phy_id_mask defines the important bits of the phy_id (and is therefore the same size) these two variables should be the same datatype. Signed-off-by: Richard Leitner --- include/linux/phy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/phy.h b/include/linux/phy.h index dc82a07cb4fd..e00fd9ce3bce 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -509,7 +509,7 @@ struct phy_driver { struct mdio_driver_common mdiodrv; u32 phy_id; char *name; - unsigned int phy_id_mask; + u32 phy_id_mask; u32 features; u32 flags; const void *driver_data; From patchwork Mon Nov 20 08:34:17 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Leitner X-Patchwork-Id: 839470 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3ygMWZ5jfcz9ryv for ; Mon, 20 Nov 2017 19:36:26 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751262AbdKTIgZ (ORCPT ); Mon, 20 Nov 2017 03:36:25 -0500 Received: from relay06.alfahosting-server.de ([109.237.142.242]:5900 "EHLO relay06.alfahosting-server.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751131AbdKTIfg (ORCPT ); Mon, 20 Nov 2017 03:35:36 -0500 Received: by relay01.alfahosting-server.de (Postfix, from userid 1001) id 8AADB32C3209; Mon, 20 Nov 2017 09:35:34 +0100 (CET) X-Spam-DCC: : X-Spam-Level: X-Spam-Status: No, score=-1000.0 required=7.0 tests=BAYES_50, D_SENT_WITH_SASL autolearn=disabled version=3.2.5 Received: from alfa3028.alfahosting-server.de (alfa3028.alfahosting-server.de [109.237.138.38]) by relay01.alfahosting-server.de (Postfix) with ESMTPS id 6C2B032C3207; Mon, 20 Nov 2017 09:35:32 +0100 (CET) Received: from localhost.localdomain (unknown [91.230.2.244]) (Authenticated sender: yes) by alfa3028.alfahosting-server.de (Postfix) with ESMTPA id 32692430D437; Mon, 20 Nov 2017 09:35:32 +0100 (CET) From: Richard Leitner To: f.fainelli@gmail.com, fugang.duan@nxp.com, andrew@lunn.ch Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, richard.leitner@skidata.com Subject: [PATCH v2 3/3] net: ethernet: fec: fix refclk enable for SMSC LAN8710/20 Date: Mon, 20 Nov 2017 09:34:17 +0100 Message-Id: <20171120083417.32558-4-dev@g0hl1n.net> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20171120083417.32558-1-dev@g0hl1n.net> References: <20171120083417.32558-1-dev@g0hl1n.net> Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org From: Richard Leitner Some PHYs (for example the SMSC LAN8710/LAN8720) doesn't allow turning the refclk on and off again during operation (according to their datasheet). Nonetheless exactly this behaviour was introduced for power saving reasons by commit e8fcfcd5684a ("net: fec: optimize the clock management to save power"). Therefore after enabling the refclk we detect if an affected PHY is attached. If so reset and initialize it again. For a better understanding here's a outline of the time response of the clock and reset lines before and after this patch: v--fec_probe() v--fec_enet_open() v v w/o patch eCLK: ___||||||||____________________||||||||||||||||| w/o patch nRST: ----__------------------------------------------ w/o patch CONF: _______XX_______________________________________ w/ patch eCLK: ___||||||||____________________||||||||||||||||| w/ patch nRST: ----__-----------------------------__----------- w/ patch CONF: _______XX_____________________________XX________ ^ ^ ^--fec_probe() ^--fec_enet_open() Generally speaking this issue is only relevant if the ref clk for the PHY is generated by the SoC. In our specific case (PCB) this problem does occur at about every 10th to 50th POR of an LAN8710 connected to an i.MX6DL SoC. The typical symptom of this problem is a "swinging" ethernet link. Similar issues were reported by users of the NXP forum: https://community.nxp.com/thread/389902 https://community.nxp.com/message/309354 With this patch applied the issue didn't occur for at least a few hundret PORs of our board. Fixes: e8fcfcd5684a ("net: fec: optimize the clock management to save power") Signed-off-by: Richard Leitner --- drivers/net/ethernet/freescale/fec_main.c | 37 +++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 06a7caca0cee..52ec9b29a70e 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -68,6 +68,7 @@ static void set_multicast_list(struct net_device *ndev); static void fec_enet_itr_coal_init(struct net_device *ndev); +static int fec_reset_phy(struct net_device *ndev); #define DRIVER_NAME "fec" @@ -1833,6 +1834,32 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, return ret; } +static int fec_enet_clk_ref_enable_reset_phy_quirk(struct net_device *ndev) +{ + struct phy_device *phy_dev = ndev->phydev; + u32 real_phy_id; + int ret; + + /* some PHYs need a reset after the refclk was enabled, so we + * reset them here + */ + if (!phy_dev) + return 0; + if (!phy_dev->drv) + return 0; + real_phy_id = phy_dev->drv->phy_id & phy_dev->drv->phy_id_mask; + switch (real_phy_id) { + case 0x0007c0f0: /* SMSC LAN8710/LAN8720 */ + ret = fec_reset_phy(ndev); + if (ret) + return ret; + ret = phy_init_hw(phy_dev); + if (ret) + return ret; + } + return 0; +} + static int fec_enet_clk_enable(struct net_device *ndev, bool enable) { struct fec_enet_private *fep = netdev_priv(ndev); @@ -1862,6 +1889,10 @@ static int fec_enet_clk_enable(struct net_device *ndev, bool enable) ret = clk_prepare_enable(fep->clk_ref); if (ret) goto failed_clk_ref; + + ret = fec_enet_clk_ref_enable_reset_phy_quirk(ndev); + if (ret) + netdev_warn(ndev, "Resetting PHY failed, connection may be unstable\n"); } else { clk_disable_unprepare(fep->clk_ahb); clk_disable_unprepare(fep->clk_enet_out); @@ -2860,11 +2891,17 @@ fec_enet_open(struct net_device *ndev) if (ret) goto err_enet_mii_probe; + /* as the PHY is connected now, trigger the reset quirk again */ + ret = fec_enet_clk_ref_enable_reset_phy_quirk(ndev); + if (ret) + netdev_warn(ndev, "Resetting PHY failed, connection may be unstable\n"); + if (fep->quirks & FEC_QUIRK_ERR006687) imx6q_cpuidle_fec_irqs_used(); napi_enable(&fep->napi); phy_start(ndev->phydev); + netif_tx_start_all_queues(ndev); device_set_wakeup_enable(&ndev->dev, fep->wol_flag &